在反应钩子之间传递数据 [英] Pass data between react hooks

查看:46
本文介绍了在反应钩子之间传递数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何将数据从一个 React hooks 表单(component)传递到另一个组件.例如,如果我需要 Profile.js 中的玩家 name 和 photo 传递并使其在 Navigation.js 中可用,我该怎么做?

Player.js

import React, { useContext , useEffect, useState } from "react";导入 { useForm } from 'react-hook-form';import { useHistory } from "react-router-dom";从axios"导入 Axios;从 '../context' 导入 UserProfileContext;const Profile = () =>{const { setData } = useContext(UserProfileContext);const [email, setEmail] = useState('');const [图片,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 历史 = useHistory();const onChangePicture = e =>{console.log('图片:', 图片);如果(e.target.files.length){setPicture(URL.createObjectURL(e.target.files[0]));} 别的 {返回假;}};//如果没有上传头像,为避免图片显示中断,显示默认图片.const addDefaultSrc = e =>{e.target.src = '/images/default-icon.png';}//将 id 传递给处理程序,以便您知道哪个项目 id 发生变化.const handleChange = (e, id) =>{e.persist();让 itemIndex;const targetPlayer = playerProfile.find((player, index) => {console.log({ 播放器, id, 索引 });itemIndex = 索引;//跟踪索引,以便您可以稍后使用它进行更新.返回 player.id === id;});console.log({ targetPlayer, id, e });const 编辑目标 = {...目标玩家,[e.target.name]: e.target.value};const tempPlayers = Array.from(playerProfile);tempPlayers[itemIndex] =editedTarget;/*//或者:如果您不想跟踪索引,您可以只映射数组const tempPlayers = playerProfile.map((profile, index) => {返回 profile.id === id ?编辑目标:个人资料;});*/设置播放器配置文件(临时播放器);setUpdateProfile({ ...updateProfile, [e.target.name]: e.target.value });//添加这个只是为了看看它是否工作};useEffect(() => {const fetchData = async() =>{尝试 {常量参数 = {电子邮件:登录用户电子邮件,};const res = await Axios.get('http://localhost:8000/service/profile', {params});setPlayerProfile(res.data.playerProfile);}赶上(e){控制台日志(e);}}fetchData();}, []);const onSubmit = () =>{设置禁用(禁用);const fetchData = async() =>{尝试 {常量参数 = {电子邮件:登录用户电子邮件,};const data = {照片:updateProfile.photo,名称:updateProfile.name,电子邮件:updateProfile.email,电话号码:updateProfile.phonenumber,位置:updateProfile.position,密码:updateProfile.password}const res = await Axios.put('http://localhost:8000/service/profile', data, {params});console.log("前端更新消息:" + res.data.success);如果(res.data.success){setIsSent(true);history.push('/')}别的 {控制台日志(res.data.message);setHelperText(res.data.message);}}赶上(e){setHelperText(e.response.data.message);}}fetchData();}返回 (<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">个人资料</h2><div className="register_profile_image"><input id="profilePic" name="photo" type="file" onChange={onChangePicture}/>

<div className="previewProfilePic" ><img alt="" onError={addDefaultSrc} name="previewImage" className="playerProfilePic_home_tile" src={photo} onChange={e =>handleChange(e, id)}></img>

<div className="fillContentDiv formElement"><标签><input className="inputRequest formContentElement" name="name" type="text" value={name}onChange={e =>handleChange(e, id)}最大长度={30}ref={注册({required: "需要全名",图案: {值:/^[a-zA-Z\s]{3,30}$/,消息:全名应至少包含 3 个字母"}})}/><span className="registerErrorTextFormat">{errors.name &&errors.name.message}</span><标签><input className="inputRequest formContentElement" name="email" type="text" value={email}onChange={e =>handleChange(e, id)}禁用={禁用}/><标签><input className="inputRequest formContentElement" name="phonenumber" type="text" value={phonenumber}onChange={e =>handleChange(e, id)}最大长度={11}ref={注册({required: "需要电话号码",图案: {值:/^[0-9\b]+$/,消息:无效的电话号码"}})}/><span className="registerErrorTextFormat">{errors.phonenumber &&errors.phonenumber.message}</span><标签><input className="inputRequest formContentElement" name="position" type="text" value={position}onChange={e =>handleChange(e, id)}最大长度={30}ref={注册({图案: {值:/^[a-zA-Z\s]{2,30}$/,消息:职位应至少有 2 个字母"}})}/><span className="registerErrorTextFormat">{errors.position &&errors.position.message}</span><标签><div className="选择" ><select name="privilege" id="select" value={privilege} onChange={e =>handleChange(e, id)}>{/**/}<option value="player">PLAYER</option>{/*<option value="admin">ADMIN</option>*/}</选择>

<标签><input className="inputRequest formContentElement" name="password" type="password" value={password}onChange={e =>handleChange(e, id)}最小长度={4}最大长度={30}ref={注册({required: "需要密码",图案: {值:/^(?=.*?\d)(?=.*?[a-zA-Z])[a-zA-Z\d]+$/,消息:密码以字母开头并包含数字!"}})}/><span className="registerErrorTextFormat">{errors.password &&errors.password.message}</span>

<标签><span className="profileValidationText">{helperText}</span><div className="submitButtonDiv formElement"><button type="submit" className="submitButton">保存</button>

))}</表单>

);}

Navigation.js

import React, { useContext } from 'react';import { NavLink, useHistory } from 'react-router-dom';从 '../context' 导入 UserProfileContext;const 导航 = () =>{const 历史 = useHistory();const { 数据 } = useContext(UserProfileContext);const divStyle = {向左飘浮',颜色:'#64cad8',填充:'0px 0px 0px 10px',字体:'Lucida,无衬线'};函数注销(){localStorage.removeItem('loginEmail')localStorage.removeItem('权限')history.push('/登录')window.location.reload(true);}return localStorage.getItem('loginEmail') &&<div className="应用程序"><div className="包装器"><nav className="siteNavigation_nav_links"><div className="clubLogo land"style={divStyle}><b>Southside Soccer</b></div><NavLink className="mobile_register_link" to="/">首页</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'>关于我们</NavLink><div className="profileImage 导航菜单"><span>{data.name}</span>|<img src=""></img>

</nav>

}导出默认导航;

App.js

import React, { useState } from 'react';导入./App.css";导入./CSSModules/home.css";导入./CSSModules/register.css";导入./CSSModules/login.css";导入./CSSModules/aboutus.css";从react-router-dom"导入 { BrowserRouter, Route, Switch };从./components/Home"导入Home;从./components/Register"导入注册;从./components/Login"导入登录;从./components/Aboutus"导入关于我们;从./components/Navigation"导入导航;从./components/Profile"导入配置文件;import { ProtectedRoute } from "./components/protected.route";从 './context' 导入 UserProfileContext;var ReactDOM = require("react-dom");const App = () =>{const [数据,setData] = useState({ID: '',名称: '',电子邮件: '',照片: '',});返回 (<UserProfileContext.Provider value={{ data, setData }}><浏览器路由器><><导航/><开关><ProtectedRoute 精确路径="/" component={Home}/><ProtectedRoute path="/profile" component={Profile}/><ProtectedRoute path="/aboutus" component={Aboutus}/><Route path="/register" component={Register}/><Route path="/login" component={Login}/></开关></></BrowserRouter></UserProfileContext.Provider>);};ReactDOM.render(React.createElement(App, null),document.getElementById("root"));导出默认应用程序;

context.js

从'react'导入React;导出默认 React.createContext();

解决方案

就像评论中提到的,一种选择是 让您的应用程序的状态保持向上(这应该是简单状态的首选选项).

实际上,这看起来像:

App.js

import React, { useState } from 'react';从'./Navigation'导入导航;从'./Profile'导入配置文件;功能应用(){const [name, setName] = useState('');返回 (<div className="应用程序"><导航名称={名称}/><小时/><Profile name={name} setName={setName}/>

);}导出默认应用程序;

Profile.js:

从'react'导入React;const Profile = ({ name, setName }) =>{返回 (<><div>个人资料:{name}</div><输入类型=文本"名称=名称"值={名称}onChange={e =>setName(e.target.value)}/></>);};导出默认配置文件;

Navigation.js:

从'react'导入React;const 导航 = ({名称}) =>{返回<div>导航:{name}</div>;};导出默认导航;

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

尝试以下操作:

context.js

从'react'导入React;导出默认 React.createContext();

App.js

import React, { useState } from 'react';从'react-router-dom'导入{ BrowserRouter, Route, Switch };导入'./styles.css';从'./components/Profile'导入配置文件;从'./components/Navigation'导入导航;从 './context' 导入 UserProfileContext;const App = () =>{const [数据,setData] = useState({id: '玩家 1',name: '玩家一号',年龄:25,照片:'玫瑰.JPG',});返回 (<UserProfileContext.Provider value={{ data, setData }}><浏览器路由器><导航/><开关><Route path="/profile" component={Profile}/></开关></BrowserRouter></UserProfileContext.Provider>);};导出默认应用程序;

components/Navigation.js

import React, { useContext } from 'react';从'react-router-dom'导入{导航链接};从 '../context' 导入 UserProfileContext;const 导航 = () =>{const { 数据 } = useContext(UserProfileContext);const divStyle = {向左飘浮',颜色:'#64cad8',填充:'0px 0px 0px 10px',字体:'Lucida,无衬线',};返回 (<div className="应用程序"><div className="包装器"><nav className="siteNavigation_nav_links"><div className="clubLogo 登陆" style={divStyle}><b>足球</b>

<NavLink className="mobile_register_link" to="/profile">轮廓</NavLink><div className="profileImage 导航菜单"><span>{data.name}</span>|<img alt="" src={data.photo}/>

</nav>

);};导出默认导航;

components/Profile.js

import React, { useContext } from 'react';导入 { useForm } from 'react-hook-form';从 '../context' 导入 UserProfileContext;const Profile = () =>{const { setData } = useContext(UserProfileContext);const { register, handleSubmit } = useForm();返回 (<div><form onSubmit={handleSubmit(setData)}><b>个人资料</b><input name="id" ref={register}/><input name="name" ref={register}/><input name="age" ref={register}/><button type="submit" className="submitButton">点击</表单>

);};导出默认配置文件;

How can I pass the data from one React hooks form (component) to another component. For example if I need player name and photo pass from Profile.js and make it available in Navigation.js, how can i do that ?

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

import React from 'react';

export default React.createContext();

解决方案

Like mentioned in the comments, one option is to left your application's state up (and that should be the preferred option for simple state).

In practice, that would look like:

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;

Edit: After a closer look at your code, I think using context API makes more sense in this case.

Try the following:

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;

这篇关于在反应钩子之间传递数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆