【问题标题】:Values are not passing and displaying even after using useContext() in react hooks即使在反应钩子中使用 useContext() 后,值也不会传递和显示
【发布时间】:2020-06-16 12:00:44
【问题描述】:

我使用useContext()Navigation.js 中获取name and photo 之类的值。我在Profile.js 中设置了<UserProfileContext.Provider value={{ updateProfile, setUpdateProfile}}>。但是仍然没有在 Navigation.js >> {updateProfile.name}|

中显示值

App.js

import React, { useState } from 'react';
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 ErrorPage from "./components/ErrorPage";
import { ProtectedRoute } from "./components/protected.route";
import UserProfileContext from './context';

var ReactDOM = require("react-dom");

const App = () => {                       

  return (
     <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} />
          <Route exact path="*" component={ErrorPage} />
      </Switch>
    </>
   </BrowserRouter>
  );
};
ReactDOM.render(
  React.createElement(App, null),
  document.getElementById("root")
);

export default App;

Navigation.js

import React, { useContext } from 'react';
import { NavLink, useHistory } from 'react-router-dom';
import UserProfileContext from '../context';


const Navigation = () => {
    const history = useHistory();
    const { updateProfile } = 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>{updateProfile.name}</span>|<img src={updateProfile.photo}></img>
                </div>
                </nav>
            </div>
        </div>
}

export default Navigation;

context.js

import React from 'react';

export default React.createContext();

Profile.js

import React, {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 [email, setEmail] = useState('');
  const [picture, setPicture] = useState('');
  const [playerProfile, setPlayerProfile] = useState([]);
  const loginUserEmail = localStorage.getItem('loginEmail');
  const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:''})
  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; 
      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;
    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}
        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 (
  <UserProfileContext.Provider value={{ updateProfile, setUpdateProfile}}>
    <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}) => (
                <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>
                  </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>
  </UserProfileContext.Provider>
  );
}

export default Profile;

【问题讨论】:

    标签: reactjs react-hooks use-context


    【解决方案1】:

    导航组件需要将 ContextProvider 放在层次结构中,但它不需要,因为 Provider 在 Profile 组件中呈现。

    您必须将 Provider 的使用移出到单独的组件中,并将其呈现为 Navigation 和 Profile 的组件祖先。发布您可以在 Navigation 和 Profile 中使用 UserContext 的帖子

    UserProfileProvider.js

    import UserProfileContext from '../context';
    const UserProfileProvider = ({children}) => {
        const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:''});
    
        const value = useMemo(() => ({
           updateProfile, setUpdateProfile
        }), [updateProfile]);
    
        return (
           <UserProfileContext.Provider value={value}>
               {children}
           </UserProfileContext.Provider>
        )   
    }
    

    App.js

    import UserProfileProvider from './UserProfileProvider.js';
    const App = () => {                       
      return (
         <BrowserRouter>
           <UserProfileProvider>
             <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} />
                  <Route exact path="*" component={ErrorPage} />
              </Switch>
           </UserProfileProvider>
       </BrowserRouter>
      );
    };
    

    Profile.js

    import UserProfileContext from '../context';
    
    const Profile = () => {
    
      const [email, setEmail] = useState('');
      const [picture, setPicture] = useState('');
      const [playerProfile, setPlayerProfile] = useState([]);
      const loginUserEmail = localStorage.getItem('loginEmail');
      const {updateProfile, setUpdateProfile} = useContext(UserProfileContext);
      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; 
          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;
        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}
            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}) => (
                    <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>
                      </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>
      );
    }
    
    export default Profile;
    

    【讨论】:

    • 但是如果我们移出到单独的组件... const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:''}); ,因为这是使用获取data 发送const res = await Axios.put('http://localhost:8000/service/profile', data, {params}); ..
    • 它使用上下文中的数据。请仔细查看配置文件中的用法。它像const {updateProfile, setUpdateProfile} = useContext(UserProfileContext); 一样使用,而不是作为状态
    • 使用您将在个人资料和导航中使用useContext 进行更新。还要确保数据从配置文件正确更新到上下文,以便您可以在导航中访问它。尽管您必须注意,除非更新配置文件中的数据,否则您不会在导航中看到它
    • 上下文不保存刷新数据,您需要将其存储在 localStorage 或其他浏览器存储中
    • 你可以在localStorage中存储base64格式的图片文件
    猜你喜欢
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    相关资源
    最近更新 更多