Исходное состояние не определено в приложении с подключением к серверу
У меня есть приложение ReactJs, которое использует Redux для управления своим магазином. Мое состояние - сложный json, поля которого могут меняться. Когда я запускаю редукторы, мне нужно указать исходное состояние, когда я обращаюсь к нему перед извлечением контента с сервера, я получаю ошибку "undefined". Ниже приведен пример,
//Test.jsx
class Test extends React.Component{
componentWillMount(){
fetchContent({
type: SET_CONTENT
});
}
render(){
return(
<div> {this.props.header} </div>
)
}
mapStateToProps(state){
return{
header: state.reducer1.a.b.c
}
}
}
export default (mapStateToProps)(Test);
//reducer1.js
export default function reducer1(state = {}, action = {}) {
switch (action.type) {
case SET_CONTENT:
return Object.assign({}, action.data);
default:
return state;
}
}
//reducer2.js
export default function reducer2(state = {}, action = {}) {
switch (action.type) {
case SET_SOMETHING_ELSE:
return Object.assign({}, action.data);
default:
return state;
}
}
//CombinedReducer.js
export default combinedReducers(Object.assign({}, {reducer1}, {reducer2}))
Теперь, когда компонент инициализируется в первый раз, state.reducer1.a.b.c
бросает неопределенный, потому что fetchContent()
на данный момент не вызывается.
Итак, мой вопрос, как мне решить эту проблему? Является ли указание начального состояния в редукторе единственным вариантом? как следующее,
//reducer1.js
export default function reducer1(state = { a: { b: { c: "somedata"}}}, action = {}) {
switch (action.type) {
case SET_CONTENT:
return Object.assign({}, action.data);
default:
return state;
}
}
2 ответа
Вы можете сделать это, но вы также можете просто обновить функцию mapState, чтобы проверить наличие первого ключа.
function mapStateToProps(state){
return{
header: state.reducer1.a ? state.reducer1.a.b.c : <div>Loading..</div>
}
}
Также я предполагаю, что вы хотите иметь mapStateToProps
вне определения класса, так как это функция, которую вы передаете connect
и не относится к компоненту:
class C {
...
}
function mapStateToProps (state) {}
connect(mapStateToProps)(C)
Наконец, вы пропустили отправку в вашем fetchContent
вызов? Использует ли это Redux-Thunk?
В большинстве случаев не следует хранить все данные ответов в редукторах. Ваша иерархия состояний не должна повторять иерархию ответа JSON.
Мне бы проще было только хранить c
переменная в редукторе:
//reducer1.js
export default function reducer1(state = { c: undefined }, action) {
switch (action.type) {
case SET_CONTENT:
return Object.assign({}, state, { c: action.data.a.b.c });
default:
return state;
}
}
Также в вашем коде есть ошибки:
mapStateToProps
функция должна быть определена вне класса- Вместо прямого звонка
fetchContent
функция, вы должны передать его результат для отправки.
// Test.jsx
class Test extends React.Component{
componentWillMount(){
dispatch(fetchContent({
type: SET_CONTENT
}));
}
render() {
const { header } = this.props;
return header ? (
<div>{header}</div>
) : (
<div>Loading...</div>
);
}
}
function mapStateToProps(state) {
return {
header: state.reducer1.c
}
}
export default (mapStateToProps)(Test);