问题
I currently have a table and each cell has a button. Upon clicking the button, based on that particular day (Monday or Tuesday), class (class 1 or class 2), and name (Kev or Josh), how can I push an object related to that particular button in the table to a new page? Using, ReactJS + React Router, what would be the correct approach to this?
And when once navigated to the new page, the new page would then populate a table with the class information from the object passed in, related to button cell clicked.
Code:
http://jsfiddle.net/k7wbzc4j/16/
Should the table rows data be structured like so and reference the object based on ID like the following, or what would be a better structure -- would like to locate that particular id object based on the cell location (with day, name, and class number taken into account)?
list: [
{
name: Kev
monday: {
class1: {
id: 0,
classTitle: abc,
number: class1,
info: {
time: 1,
classSize: 2,
}
},
class 2: {
id: 1,
classTitle: def,
number: class2,
info: {
time: 1,
classSize: 2,
}
}
},
tuesday: {
class1: {
id: 2,
classTitle: ghi,
number: class1,
info: {
time: 1,
classSize: 2,
}
},
class 2: {
id: 3,
classTitle: jkl,
number: class2,
info: {
time: 1,
classSize: 2,
}
}
},
},
{
name: Josh,
monday: {
class1: {
id: 4,
classTitle: mno,
number: class1,
info: {
time: 1,
classSize: 2,
}
},
class2: {
id: 5,
classTitle: pqr,
number: class2,
info: {
time: 1,
classSize: 2,
}
}
},
tuesday: {
class1: {
id: 6,
classTitle: stu,
number: class1,
info: {
time: 1,
classSize: 2,
}
},
class2: {
id: 7,
classTitle: vwx,
number: class2,
info: {
time: 1,
classSize: 2,
}
}
},
}
}
]
For example, if the Kev's row in Monday column, class1, would like to pass the props of the following to the next page:
class1: {
id: 0,
classTitle: abc,
number: class1,
info: {
time: 1,
classSize: 2,
}
}
Will accept and upvote answer. Thank you in advance
回答1:
This is where a centralized state management tool like redux comes in handy. You could dispatch an action (something like SELECT_CLASS
) that sets the selected class in the store, then read that value from your new component. I'd recommend this approach.
However, there is another way. Each browser history entry has a concept of state
. So, when you navigate to your new route, you can save the selected data in the state for that history entry, then read it when the component renders. It would look something like this:
Save state:
router.push({
to: '/path',
state: class1
});
To read it:
router.location.state
React router docs: https://github.com/ReactTraining/react-router/blob/master/docs/API.md#pushpathorloc
UPDATE: Yay for redux! So first, lets define the action + action creator for this:
export const SELECT_CLASS = 'SELECT_CLASS';
export const selectClass = (class) => {
return {
type: SELECT_CLASS,
class,
}
};
Now, lets take a look at what the reducer to handle this would look like:
import { SELECT_CLASS } from '/path/to/action'
const selectedClass = (
state={},
action
) => {
switch (action.type) {
case SELECT_CLASS:
return action.class;
default:
returns state;
}
};
Now, assuming you've connected your components via react-redux like this:
// First argument is mapStateToProps, the second is mapDispatchToProps
// https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options
export default connect((state) => state, { selectClass } )(YourComponent);
This is how you'll set the selected class:
// Wherever you need to navigate
function eventHandler(e) {
const { selectClass } = this.props;
selectClass(class1);
router.push('/next/location');
}
And in your next component (which should also be connected, but doesn't require mapDispatchToProps
:
render() {
const { selectedClass } = this.props;
// do what you need with the class.
}
If you need any help setting up react + redux, the docs here are fantastic. If the ES6 syntax I used looks unfamiliar, a good reference are the babel docs here
UPDATE 2: I took your fiddle and ran with it: http://jsfiddle.net/k7wbzc4j/17/. Each button has a click event that will get the correct object.
FINAL UPDATE: So here's the rundown of handleClick
handleClick(e) {
const classTitle = e.target.innerHTML;
let obj = undefined;
data.forEach((schedule) => {
['monday', 'tuesday'].forEach((day) => {
const classes = schedule[day];
return Object.keys(classes).forEach((c) => {
const cls = classes[c];
if (cls.classTitle === classTitle) {
obj = cls;
}
});
})
});
if (obj) {
// do your navigation here
}
}
First, we use forEach
to iterate over the array data
that holds all of the schedules. Then, we iterate over each day (currently only monday
and tuesday
) to get all the classes on that day for the current schedule. Then, since we don't know the names of all the classes, we just grab all of the keys (which are the class names) and iterate over those. Finally, we can get the actual class objects and check if the classTitle
matched the one that was clicked. If so, we save that object to obj
. At the very end, we ensure that we found a matching object, then do whatever is necessary to properly handle that click. That's pretty messy, but necessary given your data structure. I'd recommend trying to store this data a bit more relationally and storing each type of item separately (eg. Users
, Classes
, Days
, and Schedules
objects all in separate arrays with ids linking them together)
To address your concern that some classTitle
s will be the same, you'll have to also figure out who's schedule was clicked (and potentially the day that it was clicked). You could do this a number of ways: add a data-user
attribute to each button and grab that on click, implement a concept of a "Selected User", create a new component (maybe called UserSchedule
) that renders a row in that table and takes, as props, that user's classes. That way, you'll know that any class that matches belongs to that user. Like I said: a number of ways.
As for showing you how to pass that to a new component, I've demonstrated 2 ways above of how to do that above: through history state or storing the value in a redux reducer and receiving it as props. Doing any more would equate to me solving the entire problem for you, which I'm not going to do since the only way this stuff sticks is for you to do it yourself. Trust in yourself, follow the advice I've given, and use the internet for any specific bugs you're having and you'll come out on top!
来源:https://stackoverflow.com/questions/41231723/reactjs-react-router-how-to-reference-a-specific-object-to-pass-down-as-prope