0

Image is displaying in Profile.js screen and other areas. But when I passed the image via useContext() to display in Navigation.js, it is displaying src(unknown), may I know what is the key issue here ?

enter image description here Profile.js

const {picture, setPicture} = useContext(UserProfileContext);
const [updateProfile, setUpdateProfile] = useState({ _id: '', photo: '', name: '', email:'', phonenumber:'', position:'', privilege:'', password:''});

     const onChangePicture = e => {
        if (e.target.files.length) {
          setPreview(URL.createObjectURL(e.target.files[0]));
          setPicture(e.target.files[0]);
        } else {
          return false;
        }
      };


      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
        setProfile({ ...profile, [e.target.name]: e.target.value });
        setPicture(e.target.files[0]);
      };

    <div className="formInstructionsDiv formElement">
            <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>

UserProfileProvider.js

import UserProfileContext from '../context';

const UserProfileProvider = ({children}) => {

    const [picture, setPicture] = useState({ photo: ''});


     const value = useMemo(() => ({
        picture, setPicture
    }), [picture]);


    return (
       <UserProfileContext.Provider value={value}>
           {children}
       </UserProfileContext.Provider>
    )   
}
export default UserProfileProvider;

Navigation.js

const Navigation = () => {

    const {picture} = useContext(UserProfileContext); 

    return localStorage.getItem('loginEmail') &&
        <div className="App">
            <div className="wrapper">
                <div id="wrap">
                    <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>
                        <span className="mobile_login_link"><img className="nav_profile"src={picture.photo}></img></span>
                    </nav>
                </div>
            </div>
        </div>
}

export default Navigation;
soccerway
  • 10,371
  • 19
  • 67
  • 132

1 Answers1

1

picture is supposed to be an object according to your state declaration:

const [picture, setPicture] = useState({ photo: ''});

however when you update it you set the file object in it like setPicture(e.target.files[0]); and hence picture.photo is undefined

Another thing to note is that you cannot directly render the image from File object, you need to use FileReader and convert it into a data blob

const onChangePicture = e => {
    if (e.target.files.length) {
      setPreview(URL.createObjectURL(e.target.files[0]));
      setPicture({photo:e.target.files[0]});
    } else {
      return false;
    }
  };

then in Navigation you will use it like

const Navigation = () => {
    const [imageSrc, setImgSrc] = useState(null);
    const {picture} = useContext(UserProfileContext); 

    useEffect(() => {
       const reader = new FileReader();
       reader.addEventListener('load', () => {
           setImgSrc(reader.result);
       });
       reader.readAsDataURL(picture.photo);
    }, [picture.photo])
    return localStorage.getItem('loginEmail') &&
        <div className="App">
            <div className="wrapper">
                <div id="wrap">
                    <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>
                        <span className="mobile_login_link"><img className="nav_profile"src={imageSrc}></img></span>
                    </nav>
                </div>
            </div>
        </div>
}

export default Navigation;
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • Thank you, it throws following error > TypeError: reader.readAsDataUrl is not a function – soccerway Jun 17 '20 at 07:07
  • `reader.readAsDataURL(pitcure.photo);` There was a typo in the function name – Shubham Khatri Jun 17 '20 at 07:09
  • Sorry again, TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'. `reader.readAsDataURL(picture.photo);` – soccerway Jun 17 '20 at 07:13
  • in such a case please ensure that picture.photo is available before you execute readAsDataURL on it – Shubham Khatri Jun 17 '20 at 07:28
  • Sorry it is throwing exception, so I can't console log and see. Only if I comment the whole useEfffect() and then i can login.. – soccerway Jun 17 '20 at 07:38
  • please add a conditional check `useEffect(() => { if(picture.photo) { const reader = new FileReader(); reader.addEventListener('load', () => { setImgSrc(reader.result); }); reader.readAsDataURL(picture.photo); } }, [picture.photo])` – Shubham Khatri Jun 17 '20 at 08:02
  • Thank you for you support, it worked. If need to add to display while Registering should I need to add separate `UserRegisterProvider.js` separately or the existing one will do ? – soccerway Jun 17 '20 at 10:42
  • Can i ask one more question while login, I am getting login user photo from res.data.photo , `setLoginPhoto(res.data.photo);` Can I pass the same to `UserProfileProvider.js and receive in second diff state `const [loginPhoto, setLoginPhoto] =useState({ photo: ''});` and the `const value2 = useMemo(() => ({ loginPhoto, setLoginPhoto }), [picture]);` – soccerway Jun 17 '20 at 12:58
  • `const value = useMemo(() => ({ picture, setPicture }), [picture]);` for Profile update case and this to pass photo while login.. `const value2 = useMemo(() => ({ loginPhoto, setLoginPhoto }), [loginPhoto]); ` – soccerway Jun 17 '20 at 13:00
  • Well that would work if photo is a file object. If its a url or data blob you will have to replace the FileReader logic with something that goes along with your data tyope – Shubham Khatri Jun 17 '20 at 13:00
  • While login the json response comes as following >>> `photo":"images\\photo-1592397282634.JPG"` – soccerway Jun 17 '20 at 13:14
  • Should i create a separate `UserLoginProvider.js` for handling this case ? – soccerway Jun 17 '20 at 13:15
  • Can you please advise on this question if possible: https://stackoverflow.com/questions/62443325/how-do-we-handle-image-with-filepath-and-convert-to-base64-in-react-hooks – soccerway Jun 18 '20 at 13:24