【问题标题】:How to make state update for two independent modules如何为两个独立的模块进行状态更新
【发布时间】:2021-07-30 18:08:48
【问题描述】:

我是新来的反应并且已经被困在这个问题上两天了。登录时,您可以选择客户或商家并重定向到适当的位置。我需要将数据从客户端传递到商家端,但是虽然客户端在输入中提交时会更新,但商家端不会。即使组件有不同的路线,有什么办法可以做到这一点?我正在尝试使用的是 redux 商店,但这似乎不起作用。

src/client/FirstForm.js

import React, {createRef, useState} from "react";
import { useDispatch, useSelector } from 'react-redux'
import { addBird, incrementBird } from '../store/birds/birds';
import {connect} from 'react-redux';

function FirstForm() {

    const handleInputChange = (event) => {
        event.preventDefault();
        this.setState({
            prodDetails : event.target.value
        })
    }
    const [birdName, setBird] = useState('');
    const birds = useSelector(state => state.birds);
    const dispatch = useDispatch();

    const handleSubmit = event => {
        event.preventDefault();
        dispatch(addBird(birdName))
        setBird('');
      };

    return (
    <div className="input-container" id="subtitle-space">
    <input type="text"onChange={e => setBird(e.target.value)} value={birdName}/>
    <button type="submit" className="btn" onClick={handleSubmit}>
    </div>
    );   
}   

const mapStateToProps= state => {
    return {
        birds : state.birds
    }
}

const mapDispatchToProps = dispatch => {
    return {
        addBird: () => dispatch(addBird())
    }
}

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

src/merchant/Merchant.js

function Merchant(props) {

    const birds = useSelector(state => state.birds);
    const dispatch = useDispatch();

    return (
          <div className="placeholder">
            <h>{birds.map(bird => (<h>{bird.name} <br></br></h>))}</h>
          <div> )
           );
}

export default withRouter(Merchant);

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import {Provider} from 'react-redux';
import { createStore } from 'redux';
import birdApp from './store/birds/birds';

const store = createStore(birdApp);

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: 
serviceWorker.unregister();

src/store/birds.js

import { combineReducers } from 'redux';
const ADD_BIRD = 'ADD_BIRD';
const INCREMENT_BIRD = 'INCREMENT_BIRD';

export function addBird(bird) {
  return {
    type: ADD_BIRD,
    bird,
  }
}

export function incrementBird(bird) {
  return {
    type: INCREMENT_BIRD,
    bird
  }
}

const defaultBirds = [
  {
    name: 'robin',
    views: 1,
  }
];

function birds(state=defaultBirds, action) {
  switch (action.type) {
    case ADD_BIRD:
      state.push(
        {
          name: action.bird,
          views: 1
        })
      return state
    case INCREMENT_BIRD:
      const bird = state.find(b => action.bird === b.name);
      const birds = state.filter(b => action.bird !== b.name);
      return [
        ...birds,
        {
          ...bird,
          views: bird.views + 1
        }
      ];
    default:
      return state;
  }
}

const birdApp = combineReducers({
  birds
});

export default birdApp;

这也是我的客户端组件 src/client/client.js:

import React,{ useEffect } from 'react'; //for later security
import { withRouter } from 'react-router-dom';
import './Client.css';
import '../common/Button.css';
import '../common/TopBar.css';
import Boxes from './Boxes';
import FirstForm from './FirstForm';
import SecondForm from './SecondForm';
import ThirdForm from './ThirdForm';
import RequestNow from './RequestNow';



class Client extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
      }
    }
    render() {
    return(
        <div>
          {/* Request now button */}
          <RequestNow></RequestNow> 

          {/* Boxes in middle */}
          <Boxes></Boxes>

          {/* Request now first form */}
          <FirstForm></FirstForm>

          {/* Request now second form */}
          <SecondForm></SecondForm>

          <ThirdForm></ThirdForm>

        </div>
      )
    }
}


export default withRouter(Client);

这是登录表单 src/components/loginform/LoginForm.js

import React, {useState} from 'react';
import axios from 'axios';
import {API_BASE_URL, ACCESS_TOKEN_NAME} from '../../constants/apiContants';
import { withRouter } from "react-router-dom";
import "../../common/Button.css";
import "../../common/Security.css";

function LoginForm(props) {
    const [state , setState] = useState({
        email : "",
        password : "",
        successMessage: null,
        client : false,
        merchant : false
    })
    const handleChange = (e) => {
        const {id , value} = e.target   
        setState(prevState => ({
            ...prevState,
            [id] : value
        }))
    }
    const redirectToClient = () => {
        props.updateTitle('Client')
        props.history.push('/client');
    }
    const redirectToMerchant = () => {
        props.updateTitle('Merchant')
        props.history.push('/merchant');
    }
    const handleClient = () => {
        //Only select if client is unselected
        if(state.client === false) {
            state.client = true;
            state.merchant = false;

            document.getElementById("client").className = "left button-selected";
            document.getElementById("merchant").className = "right button-unselected";
        }
    } 
    const handleMerchant = () => {
        //Do nothing if merchant is already selected
        if(state.merchant === false) {
            state.merchant = true;
            state.client = false;
            
            document.getElementById("merchant").className = "right button-selected";
            document.getElementById("client").className = "left button-unselected";
        }
    } 
    const handleSubmitClick = (e) => {
        e.preventDefault();
        if(state.client === false && state.merchant === false) {
            props.showError('Please select client or merchant');
        }
        else {
        const payload={
            "email":state.email,
            "password":state.password,
        }
        axios.post(API_BASE_URL+'/user/login', payload)
            .then(function (response) {
                if(response.status === 200){
                    setState(prevState => ({
                        ...prevState,
                        'successMessage' : 'Login successful. Redirecting to home page..'
                    }))
                    localStorage.setItem(ACCESS_TOKEN_NAME,response.data.token);
                    if(state.client) {
                        redirectToClient();
                        }
                    else if(state.merchant) {
                        redirectToMerchant();
                    }
                    props.showError(null)
                }
                else if(response.code === 204){
                    props.showError("Username and password do not match");
                }
                else{
                    props.showError("Username does not exists");
                }
            })
            .catch(function (error) {
                console.log(error);
            });
    }}
    const redirectToRegister = () => {
        props.history.push('/register'); 
        props.updateTitle('Register');
    }
    return(
        <div className="card col-12 col-lg-4 login-card mt-2 hv-center">
            <form>
                <div className="form-group text-left">
                <label htmlFor="exampleInputEmail1">Email address</label>
                <input type="email" 
                       className="form-control" 
                       id="email" 
                       aria-describedby="emailHelp" 
                       placeholder="Enter email" 
                       value={state.email}
                       onChange={handleChange}
                />
                <small id="emailHelp" className="form-text text-muted">We'll never share your email with anyone else.</small>
                </div>
                <div className="form-group text-left">
                <label htmlFor="exampleInputPassword1">Password</label>
                <input type="password" 
                       className="form-control" 
                       id="password" 
                       placeholder="Password"
                       value={state.password}
                       onChange={handleChange} 
                />
                </div>
                <div className="form-check">
                </div>
                <div className="btnContainer" id="clientMerchButton">
                    <span id="client" class="left button-unselected"
                        onClick={handleClient}>
                    Client</span>

                    <span id="merchant" class="right button-unselected"
                        onClick={handleMerchant}>
                    Merchant</span>
                </div> <br></br> <br></br>
                <button 
                    type="submit" 
                    className="btn btn-primary"
                    id="loginSubmit"
                    onClick={handleSubmitClick}
                >Submit</button>
            </form>
            <div className="alert alert-success mt-2" style={{display: state.successMessage ? 'block' : 'none' }} role="alert">
                {state.successMessage}
            </div>
            <div className="registerMessage">
                <span>Dont have an account? </span>
                <span className="loginText" onClick={() => redirectToRegister()}>Register</span> 
            </div>
        </div>
    )
}

export default withRouter(LoginForm);

【问题讨论】:

  • 据我了解,您有两条路线:merchantclient,您能否同时发布您的router 组件和client 组件,并告诉我们您的数据是什么想通过吗?
  • 我已经编辑了我的帖子。现在我只是想通过更新的鸟类数组作为测试(它有一个名称和视图)。提交到 FirstForm.js 中的表单应该将元素添加到 Birds 数组,并且此更新不会显示在商家端,即使它确实出现在客户端 FirstForm 上。
  • 很抱歉我还没有发现问题,但我注意到奇怪的 jsx 元素 'h' &lt;h&gt;{birds.map(bird =&gt; (&lt;h&gt;{bird.name} &lt;br&gt;&lt;/br&gt;&lt;/h&gt;))}&lt;/h&gt;,你的意思是 h1?,你能尝试在您的Merchant 组件中也控制台记录birds 变量,看看您有什么。
  • 那只是在客户端显示鸟类列表的所有元素。当我在商家端 console.log(birds) 时,我得到的只是鸟的初始状态,它只是 {name : 'robin', value : 1} 没有添加额外的鸟
  • 您在Merchant 中的代码看起来不错,但您可以尝试使用connect 函数而不是useSelector 以确保``` function Merchant(props){ console.log( {props}) //... } const mapStateToProps= state => { return { bird : state.birds } } export default withRouter(connect(mapStateToProps)(Merchant)); ```

标签: javascript reactjs react-native redux react-hooks


【解决方案1】:

如果这是最新的代码,那么您需要在单击按钮时使用 handleSubmit,因为我看不到在任何地方使用了 handleSubmit。另外在onChange上使用handleChange函数会更好。

 <div className="input-container" id="subtitle-space" onSubmit="handleSubmit">
    <input type="text"onChange={handleInputChange} value={birdName}/>
    <input type="submit" value="Send Request">
 </div>

并且 mapStateToProps 和 mapDispatchToProps 不是必需的,因为您已经在使用 useDispatch 和 useSelector

【讨论】:

  • 我忘记在我的帖子中包含该按钮,但它现在在那里。我遇到的问题是商家端的数据更新,因为它正在客户端更新。
  • do const birds = useSelector(state =&gt; state.birds); 也在客户端更新,你可以试试case ADD_BIRD: return{ ...state, name: action.bird } 而不是 push in reducer
猜你喜欢
  • 2016-08-08
  • 2022-08-02
  • 2020-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 1970-01-01
  • 2020-03-31
相关资源
最近更新 更多