在反应挂钩之间传递数据

时间:2020-06-15 10:30:32

标签: javascript reactjs typescript react-hooks

如何将数据从一个[HttpPost] public ActionResult Insert(<SomeOtherModel> otherModel, IEnumberable<Test> model){ foreach (var item in model){ //to do here } } 表单( component )传递到另一个组件。例如,如果我需要玩家React hooksname and photo传球并使其在Profile.js中可用,我该怎么做?

Navigation.js

Player.js

import React, { useContext , useEffect, useState } from "react"; import { useForm } from 'react-hook-form'; import { useHistory } from "react-router-dom"; import Axios from "axios"; import UserProfileContext from '../context'; const Profile = () => { const { setData } = useContext(UserProfileContext); const [email, setEmail] = useState(''); const [picture, setPicture] = useState(''); const [playerProfile, setPlayerProfile] = useState([]); const loginUserEmail = localStorage.getItem('loginEmail'); const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:'', phonenumber: '', position: '', password: '' }) const [isSent, setIsSent] = useState(false); const [helperText, setHelperText] = useState(''); const [disabled, setDisabled] = useState(true); const { handleSubmit, register, errors } = useForm(); const history = useHistory(); const onChangePicture = e => { console.log('picture: ', picture); if (e.target.files.length) { setPicture(URL.createObjectURL(e.target.files[0])); } else { return false; } }; // If no profile image is being uploaded, to avoid the broken display of image, display a default image. const addDefaultSrc = e => { e.target.src = '/images/default-icon.png'; } // Pass the id to the handler so you will know which item id changing. const handleChange = (e, id) => { e.persist(); let itemIndex; const targetPlayer = playerProfile.find((player, index) => { console.log({ player, id, index }); itemIndex = index; // Track the index so you can use it to update later. return player.id === id; }); console.log({ targetPlayer, id, e }); const editedTarget = { ...targetPlayer, [e.target.name]: e.target.value }; const tempPlayers = Array.from(playerProfile); tempPlayers[itemIndex] = editedTarget; /* // Alternatively:: you can just map over the array if you dont want to track the index const tempPlayers = playerProfile.map((profile, index) => { return profile.id === id ? editedTarget : profile; }); */ setPlayerProfile(tempPlayers); setUpdateProfile({ ...updateProfile, [e.target.name]: e.target.value }); // this is added just to see if its working }; useEffect(() => { const fetchData = async () => { try { const params = { email: loginUserEmail, }; const res = await Axios.get('http://localhost:8000/service/profile', {params}); setPlayerProfile(res.data.playerProfile); } catch (e) { console.log(e); } } fetchData(); }, []); const onSubmit = () => { setDisabled(disabled); const fetchData = async () => { try { const params = { email: loginUserEmail, }; const data = {photo: updateProfile.photo, name: updateProfile.name, email: updateProfile.email, phonenumber: updateProfile.phonenumber, position: updateProfile.position, password: updateProfile.password} const res = await Axios.put('http://localhost:8000/service/profile', data, {params}); console.log("Front End update message:" + res.data.success); if (res.data.success) { setIsSent(true); history.push('/') } else { console.log(res.data.message); setHelperText(res.data.message); } } catch (e) { setHelperText(e.response.data.message); } } fetchData(); } return ( <div className="register_wrapper"> <div className="register_player_column_layout_one"> <div className="register_player_Twocolumn_layout_two"> <form onSubmit={handleSubmit(onSubmit)} className="myForm"> { playerProfile.map(({ id, photo, name, email, phonenumber, position, privilege, password }) => ( <div key={id}> <div className="formInstructionsDiv formElement"> <h2 className="formTitle">Profile</h2> <div className="register_profile_image"> <input id="profilePic" name="photo" type="file" onChange={onChangePicture} /> </div> <div className="previewProfilePic" > <img alt="" onError={addDefaultSrc} name="previewImage" className="playerProfilePic_home_tile" src={photo} onChange={e => handleChange(e, id)}></img> </div> </div> <div className="fillContentDiv formElement"> <label> <input className="inputRequest formContentElement" name="name" type="text" value={name} onChange={e => handleChange(e, id)} maxLength={30} ref={register({ required: "Full name is required", pattern: { value: /^[a-zA-Z\s]{3,30}$/, message: "Full name should have minimum of 3 letters" } })} /> <span className="registerErrorTextFormat">{errors.name && errors.name.message}</span> </label> <label> <input className="inputRequest formContentElement" name="email" type="text" value={email} onChange={e => handleChange(e, id)} disabled={disabled} /> </label> <label> <input className="inputRequest formContentElement" name="phonenumber" type="text" value={phonenumber} onChange={e => handleChange(e, id)} maxLength={11} ref={register({ required: "Phone number is required", pattern: { value: /^[0-9\b]+$/, message: "Invalid phone number" } })} /> <span className="registerErrorTextFormat">{errors.phonenumber && errors.phonenumber.message}</span> </label> <label> <input className="inputRequest formContentElement" name="position" type="text" value={position} onChange={e => handleChange(e, id)} maxLength={30} ref={register({ pattern: { value: /^[a-zA-Z\s]{2,30}$/, message: "Position should have minimum of 2 letters" } })} /> <span className="registerErrorTextFormat">{errors.position && errors.position.message}</span> </label> <label> <div className="select" > <select name="privilege" id="select" value={privilege} onChange={e => handleChange(e, id)}> {/*<option selected disabled>Choose an option</option> */} <option value="player">PLAYER</option> {/*<option value="admin">ADMIN</option>*/} </select> </div> </label> <label> <input className="inputRequest formContentElement" name="password" type="password" value={password} onChange={e => handleChange(e, id)} minLength={4} maxLength={30} ref={register({ required: "Password is required", pattern: { value: /^(?=.*?\d)(?=.*?[a-zA-Z])[a-zA-Z\d]+$/, message: "Password begin with a letter and includes number !" } })} /> <span className="registerErrorTextFormat">{errors.password && errors.password.message}</span> </label> </div> <label> <span className="profileValidationText">{helperText}</span> </label> <div className="submitButtonDiv formElement"> <button type="submit" className="submitButton">Save</button> </div> </div> )) } </form> </div> </div> </div> ); }

Navigation.js

import React, { useContext } from 'react'; import { NavLink, useHistory } from 'react-router-dom'; import UserProfileContext from '../context'; const Navigation = () => { const history = useHistory(); const { data } = useContext(UserProfileContext); const divStyle = { float:'left', color: '#64cad8', padding: '0px 0px 0px 10px', font:'Lucida, sans-serif' }; function logout() { localStorage.removeItem('loginEmail') localStorage.removeItem('Privilege') history.push('/login') window.location.reload(true); } return localStorage.getItem('loginEmail') && <div className="App"> <div className="wrapper"> <nav className="siteNavigation_nav_links"> <div className="clubLogo landing"style={divStyle}><b>Southside Soccer</b></div> <NavLink className="mobile_register_link" to="/">Home</NavLink> <NavLink className="mobile_register_link" to="/profile">Profile</NavLink> <NavLink className="mobile_login_link" to="/login" onClick={logout}>Logout</NavLink> <NavLink className="mobile_login_link" to='/aboutus'>About us</NavLink> <div className="profileImage nav menu"> <span>{data.name}</span>|<img src=""></img> </div> </nav> </div> </div> } export default Navigation;

App.js

import React, { useState } from 'react'; import "./App.css"; import "./CSSModules/home.css"; import "./CSSModules/register.css"; import "./CSSModules/login.css"; import "./CSSModules/aboutus.css"; import { BrowserRouter, Route, Switch } from "react-router-dom"; import Home from "./components/Home"; import Register from "./components/Register"; import Login from "./components/Login"; import Aboutus from "./components/Aboutus"; import Navigation from "./components/Navigation"; import Profile from "./components/Profile"; import { ProtectedRoute } from "./components/protected.route"; import UserProfileContext from './context'; var ReactDOM = require("react-dom"); const App = () => { const [data, setData] = useState({ id: '', name: '', email: '', photo: '', }); return ( <UserProfileContext.Provider value={{ data, setData }}> <BrowserRouter> <> <Navigation /> <Switch> <ProtectedRoute exact path="/" component={Home} /> <ProtectedRoute path="/profile" component={Profile} /> <ProtectedRoute path="/aboutus" component={Aboutus} /> <Route path="/register" component={Register} /> <Route path="/login" component={Login} /> </Switch> </> </BrowserRouter> </UserProfileContext.Provider> ); }; ReactDOM.render( React.createElement(App, null), document.getElementById("root") ); export default App;

context.js

3 个答案:

答案 0 :(得分:1)

使用React的内置上下文API。将应用程序包装在上下文提供程序中,然后可以使用useContext钩子访问状态,在组件之间分派状态更新。

应用程序级别设置-一次

// Define Context
const AppContext = React.createContext()

// Define initial state
const initialState = {}

// Define Reducer
const Reducer = (state, dispatch) => {
  switch(action.type) {
    case "ACTION_TYPE": return {...state, prop: action.payload}
    default: return state
  }
}


//Wrap main App in context, pass state from React's useReducer hook
const [state, dispatch] = useReducer(Reducer, initialState)
<AppContext.Provider data={{
  state,
  dispatch
}}>
  <ReactAppMainWrapper />
</AppContext.Provider>

组件级别

const {state, dispatch} = useContext(AppContext);

// to update state call dispatch from anywhere, all components consuming state will be updated

dispatch({
   type: "ACTION_TYPE",
   payload: "new_value"
})

说明

状态就像商店一样在整个应用程序中都可用。

在任何组件中,导入AppContext并使用React的内置useContext挂钩与组件中的商店进行交互。

可以从上面的上下文提供者中传递的数据对象。

答案 1 :(得分:1)

就像评论中提到的那样,一个选项是left your application's state up(这应该是简单状态的首选选项)。

实际上,它看起来像:

App.js

import React, { useState } from 'react';

import Navigation from './Navigation';
import Profile from './Profile';

function App() {
  const [name, setName] = useState('');

  return (
    <div className="App">
      <Navigation name={name} />
      <hr />
      <Profile name={name} setName={setName} />
    </div>
  );
}

export default App;

Profile.js:

import React from 'react';

const Profile = ({ name, setName }) => {
  return (
    <>
      <div>Profile: {name}</div>
      <input
        type="text"
        name="name"
        value={name}
        onChange={e => setName(e.target.value)}
      />
    </>
  );
};

export default Profile;

Navigation.js:

import React from 'react';

const Navigation = ({ name }) => {
  return <div>Navigation: {name}</div>;
};

export default Navigation;

编辑:仔细查看您的代码后,我认为在这种情况下使用上下文API更有意义。

尝试以下操作:

context.js

import React from 'react';

export default React.createContext();

App.js

import React, { useState } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';

import './styles.css';
import Profile from './components/Profile';
import Navigation from './components/Navigation';
import UserProfileContext from './context';

const App = () => {
  const [data, setData] = useState({
    id: 'player-1',
    name: 'Player One',
    age: 25,
    photo: 'rose.JPG',
  });

  return (
    <UserProfileContext.Provider value={{ data, setData }}>
      <BrowserRouter>
        <Navigation />
        <Switch>
          <Route path="/profile" component={Profile} />
        </Switch>
      </BrowserRouter>
    </UserProfileContext.Provider>
  );
};

export default App;

components / Navigation.js

import React, { useContext } from 'react';
import { NavLink } from 'react-router-dom';

import UserProfileContext from '../context';

const Navigation = () => {
  const { data } = useContext(UserProfileContext);

  const divStyle = {
    float: 'left',
    color: '#64cad8',
    padding: '0px 0px 0px 10px',
    font: 'Lucida, sans-serif',
  };

  return (
    <div className="App">
      <div className="wrapper">
        <nav className="siteNavigation_nav_links">
          <div className="clubLogo landing" style={divStyle}>
            <b>Soccer</b>
          </div>

          <NavLink className="mobile_register_link" to="/profile">
            Profile
          </NavLink>

          <div className="profileImage nav menu">
            <span>{data.name}</span> | <img alt="" src={data.photo} />
          </div>
        </nav>
      </div>
    </div>
  );
};

export default Navigation;

components / Profile.js

import React, { useContext } from 'react';
import { useForm } from 'react-hook-form';

import UserProfileContext from '../context';

const Profile = () => {
  const { setData } = useContext(UserProfileContext);
  const { register, handleSubmit } = useForm();

  return (
    <div>
      <form onSubmit={handleSubmit(setData)}>
        <b>Profile</b>
        <input name="id" ref={register} />
        <input name="name" ref={register} />
        <input name="age" ref={register} />
        <button type="submit" className="submitButton">
          Click
        </button>
      </form>
    </div>
  );
};

export default Profile;

答案 2 :(得分:0)

您可以利用react-redux进行全局状态处理,或将回调函数从Navigation.js传递到Profile.js