React / Redux-对应用程序加载/初始化的调度动作

我有来自服务器的令牌身份验证,因此在最初加载我的Redux应用程序时,我需要向该服务器发出请求,以检查用户是否已通过身份验证,如果是,我应该获得令牌。

我发现不建议使用Redux核心INIT操作,因此如何在呈现应用程序之前调度操作?

NearGilSam2020/03/16 15:22:05

我正在使用redux-thunk从应用程序init的API端点获取用户下的帐户,并且它是异步的,因此数据在我的应用程序渲染后传入,并且上面的大多数解决方案对我来说并不奇怪,有些是折旧。因此我查看了componentDidUpdate()。因此,基本上在APP初始化上,我必须具有API的帐户列表,并且我的redux存储帐户将为null或[]。此后求助于此。

class SwitchAccount extends Component {

    constructor(props) {
        super(props);

        this.Format_Account_List = this.Format_Account_List.bind(this); //function to format list for html form drop down

        //Local state
        this.state = {
                formattedUserAccounts : [],  //Accounts list with html formatting for drop down
                selectedUserAccount: [] //selected account by user

        }

    }



    //Check if accounts has been updated by redux thunk and update state
    componentDidUpdate(prevProps) {

        if (prevProps.accounts !== this.props.accounts) {
            this.Format_Account_List(this.props.accounts);
        }
     }


     //take the JSON data and work with it :-)   
     Format_Account_List(json_data){

        let a_users_list = []; //create user array
        for(let i = 0; i < json_data.length; i++) {

            let data = JSON.parse(json_data[i]);
            let s_username = <option key={i} value={data.s_username}>{data.s_username}</option>;
            a_users_list.push(s_username); //object
        }

        this.setState({formattedUserAccounts: a_users_list}); //state for drop down list (html formatted)

    }

     changeAccount() {

         //do some account change checks here
      }

      render() {


        return (
             <Form >
                <Form.Group >
                    <Form.Control onChange={e => this.setState( {selectedUserAccount : e.target.value})} as="select">
                        {this.state.formattedUserAccounts}
                    </Form.Control>
                </Form.Group>
                <Button variant="info" size="lg" onClick={this.changeAccount} block>Select</Button>
            </Form>
          );


         }    
 }

 const mapStateToProps = state => ({
      accounts: state.accountSelection.accounts, //accounts from redux store
 });


  export default connect(mapStateToProps)(SwitchAccount);
Davaid番长十三2020/03/16 15:22:05

我对为此提出的任何解决方案都不满意,然后想到我正在考虑需要呈现的类。如果我刚刚创建了一个用于启动的类,然后将其推送到componentDidMount方法中并仅render显示加载屏幕呢?

<Provider store={store}>
  <Startup>
    <Router>
      <Switch>
        <Route exact path='/' component={Homepage} />
      </Switch>
    </Router>
  </Startup>
</Provider>

然后有这样的事情:

class Startup extends Component {
  static propTypes = {
    connection: PropTypes.object
  }
  componentDidMount() {
    this.props.actions.initialiseConnection();
  }
  render() {
    return this.props.connection
      ? this.props.children
      : (<p>Loading...</p>);
  }
}

function mapStateToProps(state) {
  return {
    connection: state.connection
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(Actions, dispatch)
  };
}

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

然后编写一些redux操作来异步初始化您的应用程序。工作请客。

西门猪猪2020/03/16 15:22:05

您可以在Root componentDidMount方法中分派操作,并且可以在render方法中验证身份验证状态。

像这样:

class App extends Component {
  componentDidMount() {
    this.props.getAuth()
  }

  render() {
    return this.props.isReady
      ? <div> ready </div>
      : <div>not ready</div>
  }
}

const mapStateToProps = (state) => ({
  isReady: state.isReady,
})

const mapDispatchToProps = {
  getAuth,
}

export default connect(mapStateToProps, mapDispatchToProps)(App)
凯泡芙A2020/03/16 15:22:05

更新:此答案适用于React Router 3

我使用react-router onEnter道具解决了这个问题这是代码的样子:

// this function is called only once, before application initially starts to render react-route and any of its related DOM elements
// it can be used to add init config settings to the application
function onAppInit(dispatch) {
  return (nextState, replace, callback) => {
    dispatch(performTokenRequest())
      .then(() => {
        // callback is like a "next" function, app initialization is stopped until it is called.
        callback();
      });
  };
}

const App = () => (
  <Provider store={store}>
    <IntlProvider locale={language} messages={messages}>
      <div>
        <Router history={history}>
          <Route path="/" component={MainLayout} onEnter={onAppInit(store.dispatch)}>
            <IndexRoute component={HomePage} />
            <Route path="about" component={AboutPage} />
          </Route>
        </Router>
      </div>
    </IntlProvider>
  </Provider>
);