【问题标题】:React props not updating on dispatch actionReact 道具未在调度操作中更新
【发布时间】:2016-10-28 09:09:56
【问题描述】:

我这几天一直在寻找答案,这真的很令人沮丧。我最近才开始学习 React,遇到了这个麻烦: 我有一个项目reducer,它是这个(projectReducers.js):

const projectReducer = (state = {
        fetching: false,
        fetched: false,
        item: {},
        items: []
    }, action) => 
{
switch(action.type){

    case 'GET_PROJECT_START':{
        state = { ...state, fetching: true};
    }
        break;
    case 'GET_PROJECT_RECEIVED':{
        state = {...state,  fetching: false, fetched: true, item: action.payload };
    }
        break;
    case 'GET_PROJECT_ERROR':{
        state = { ...state, fetching: false, error: action.payload };
    }


    case 'GET_PROJECTS_START':{
        state = { ...state, fetching: true};
    }
        break;
    case 'GET_PROJECTS_RECEIVED':{
        state = {...state,  fetching: false, fetched: true, items: action.payload };
    }
        break;
    case 'GET_PROJECTS_ERROR':{
        state = { ...state, fetching: false, error: action.payload };
    }
}
return state
};

export default projectReducer;

附:我知道 GET_PROJECT_START 和 GET_PROJECTS_START 的作用相同,我暂时将它们分开只是为了我自己清楚。

动作(projectActions.js):

export function createProject(number){
    return {
        type: 'CREATE_PROJECT',
        payload: number
        }
};

export function getProjectStart(){
    return {
        type: 'GET_PROJECT_START'
    }
};

export function getProjectReceived(project){
    return {
        type: 'GET_PROJECT_RECEIVED',
        payload: project
    }
};

export function getProjectError(err){
    return {
        type: 'GET_PROJECT_ERROR',
        payload: err
    }
};

export function getProjectsStart(){
    return {
        type: 'GET_PROJECTS_START'
    }
};

export function getProjectsReceived(projects){
    return {
        type: 'GET_PROJECTS_RECEIVED',
        payload: projects
    }
};

export function getProjectsError(err){
    return {
        type: 'GET_PROJECTS_ERROR',
        payload: err
    }
};

我将我的 reducer 与 combineReducers 组合并创建 store (store.js):

import {createStore, combineReducers, applyMiddleware} from 'redux';
import logger from 'redux-logger';

import mathReducer from './reducers/mathReducer'; //not relevant
import userReducer from './reducers/userReducer'; //not relevant
import projectReducer from './reducers/projectReducer';

export default createStore(
    combineReducers({mathReducer, userReducer, projectReducer}),
    {},
    applyMiddleware(logger()) <- log changes
);

从 react-redux 将根组件包装在 Provider 中以绑定存储(Index.js)

render(
    <Provider store={store}>
        <App/>
    </Provider>,
    window.document.getElementById('app')
);

并使用 connect (App.js) 将 store 绑定到 root app props

class App extends React.Component {

    render() {
        return (
            <Router history={browserHistory}>
                <Route path="/login" component={Login}/>
                <Route path="/" component={Dashboard}>
                    <IndexRoute component={Home}/>
                    <Route path="/home" component={Home}/>
                    <Route path="/blank" project={this.props.project} projectActions={this.props.projectActions} component={Projects}/>
                </Route>
            </Router>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        math: state.mathReducer,
        user: state.userReducer,
        project: state.projectReducer
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        projectActions :{
            getProjectStart: () => {dispatch(getProjectStart())},
            getProjectReceived: (project) => {dispatch(getProjectReceived(project))},
            getProjectError: (err) => {dispatch(getProjectError(err))},
            getProjectsStart: () => {dispatch(getProjectsStart())},
            getProjectsReceived: (project) => {dispatch(getProjectsReceived(project))},
            getProjectsError: (err) => {dispatch(getProjectsError(err))}
        }
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

然后使用(Projects.js)中传递的道具从服务器获取:

export default class Projects extends React.Component {

    fetchProjects() {
        let projectActions = this.props.route.projectActions;
        projectActions.getProjectsStart();
        console.log(this.props.route.project);

        fetch('http://localhost:3000/projects/').then((response)=> {
            setTimeout(() => {
                projectActions.getProjectsReceived(response.json());
                console.log(this.props.route.project);
            }, 5000);

        })
    }

    componentWillMount() {
        this.fetchProjects();
    }

    render() {
        return (
            <div>
                <div className="row">
                    <h1>Projects</h1>
                    {this.props.route.project.fetching ? <span> receiving data</span> : <span> Not receiving data </span>}
                </div>
            </div>
        )
    }
}

这里发生了有趣的事情,this.props.route.project 永远不会更新 span->即使我添加了 5 秒的巨大延迟,也不会接收数据永远不会改变。然而显示 (prev state | action | next state) 的 redux-logger 显示了所有正确的更改。我的绑定哪里出错了?

【问题讨论】:

  • 在我的情况下起作用的是,在 React 路由器中添加了调度程序 onEnter。为此,您将需要 redux-thunk,github.com/gaearon/redux-thunk
  • 现在我完全搞砸了:D 为什么如果我使用你的方法,通过添加 onEnter={this.fetchProjects} 它可以正确获取它们,为什么我不能将调度程序作为属性传递? :D 因为如果我使用 onEnter 我必须将它们添加到 nextState 并且据我所知它们应该作为属性传递,因为状态已经由 redux store 管理:)
  • 然而,如果我在父组件中执行获取,子组件仍然没有得到更新:/
  • 好的,现在我将连接移动到子组件,一切似乎都可以正常工作,但这要求每个需要访问存储对象或调度程序的组件都应该与 react-redux 连接? :)
  • 是的,完全正确。管理起来有点棘手,但效果很好。

标签: javascript reactjs redux react-redux


【解决方案1】:

componentWillMount 在渲染之前运行,如果你想要一个动作来影响你的渲染,你应该使用 componentDidMount。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 2017-11-09
    • 1970-01-01
    相关资源
    最近更新 更多