0

Please, I need help accessing a <trix-editor> element in my Mutation component. I'm using React hook useRef() to access this, but getting null. From Chrome Dev Tools (image below) I can see the element has been referred. I have tried some of the solutions given here & here but with no luck. Problem seems to be in the rendering of the Mutation component. I'm fairly new to React, so not sure if I'm getting this right. What am I doing wrong? Thank you in advance for your help.


enter image description here

My code:

const EditProfile = () => {
  const trixInput = useRef(null);
  const [state, setState] = useState({
                              firstName: "",
                              lastName: "",
                              bio: "",
                              avatar: "",
                              gender: "",
                              country: ""
                            });

  let userID
  let { username }    = useParams();
  let userFromStore   = JSON.parse(sessionStorage.getItem('_ev')));
  let history         = useHistory();

  useEffect(() => {
    // trixInput.current.addEventListener("trix-change", event => {
       console.log(trixInput.current); // <<<< this prints null to the screen 
    // })
  },[]);

  if (userFromStore !== username) {
    return (
      <div className="alert">
         <span className="closebtn" onClick={() => history.push("/console")}>&times;</span>
          <strong>Wanning!</strong> Not authorized to access this page.
      </div>
    );
  }
  return (
    <Query query={GetAuthUser}>
      {({ loading, error, data }) => {
        if (loading) return "loading...";
        if (error)   return `Error: ${error}`;

        if (data) {
          let {userId, firstName, lastName, avatar, bio, gender, country} = data.authUser.profile;
          userID = parseInt(userId);

          return (
            <Mutation mutation={UpdateUserProfile}>
              {(editProfile, { loading }) => (
                <div  className="card bg-light col-md-8 offset-md-2 shadow p-3 mb-5 rounded">
                  <article className="card-body">
                    <form onSubmit={ e => {
                      e.preventDefault();
                      editProfile({
                        variables: {
                          userId:    userID,
                          firstName: state.firstName,
                          lastName:  state.lastName,
                          bio:       state.bio,
                          avatar:    state.avatar,
                          gender:    state.gender,
                          country:   state.country
                        }
                      }).then(({ data: { editProfile: { success, errors }  } }) => {
                        success ? alert(success) : alert(errors[0]["message"]);
                      });
                    }}
                    >
                    <div className="form-row mb-3">
                      <div className="col">
                        <input
                          type="text"
                          name="firstName"
                          placeholder="First name"
                          className="form-control"
                          defaultValue={firstName}
                          onChange={e => setState({firstName: e.currentTarget.value})}
                        />
                      </div>
                      <div className="col">
                        <input
                          type="text"
                          name="lastName"
                          placeholder="Last name"
                          className="form-control"
                          defaultValue={lastName}
                          onChange={e => setState({lastName: e.currentTarget.value})}
                        />
                      </div>
                    </div>
                    <div className="form-group">
                      <label className="">Bio</label>
                      <input
                        type="hidden"
                        defaultValue={bio}
                        name="bio"
                        id="bio-body"
                      />
                      // <<< having trouble accessing this ref element
                      <trix-editor input="bio-body" ref={trixInput}/>
                    </div>

                    <input type="submit" className="btn btn-primary" value="Update Profile" disabled={loading}/>
                    </form>
                  </article>
                </div>
              )}
            </Mutation>
          );
        }
      }}
    </Query>
  )
}

export default EditProfile;

UPDATE: For anyone interested, problem was solved by extracting Mutation component to a different file. Reason been Mutation component wasn't mounting on render, only the Query component was mounting. First iteration of the solution is shown as an answer.

2
  • I 'm learning now that only the Query component mounts at render. Therefore not able to ref trix-editor inside Mutation. But what are you supposed to do in this situation? I want to submit the new content to server on submit, but I have no access to this info. Commented Apr 16, 2020 at 18:30
  • Problem solved. Please see answer if interested. Commented Apr 16, 2020 at 19:22

1 Answer 1

0

EditProfile component

import React, { useState } from 'react';
import { Query  } from 'react-apollo';
import { useHistory, useParams } from "react-router-dom";
import { GetAuthUser } from './operations.graphql';
import ProfileMutation from './ProfileMutation'


const EditProfile = (props) => {
  const [state, setState] = useState({
                              firstName: "",
                              lastName: "",
                              bio: "",
                              avatar: "",
                              gender: "",
                              country: ""
                            });

  let { username }    = useParams();
  let userFromStore   = JSON.parse(sessionStorage.getItem('_ev'));
  let history         = useHistory();

  if (userFromStore !== username) {
    return (
      <div className="alert">
         <span className="closebtn" onClick={() => history.push("/console")}>&times;</span>
          <strong>Wanning!</strong> Not authorized to access this page.
      </div>
    );
  }
  return (
    <Query query={GetAuthUser}>
      {({ loading, error, data }) => {
        if (loading) return "loading...";
        if (error)   return `Error: ${error}`;

        return <ProfileMutation state={state} profile={data.authUser.profile} setState={setState}/>
      }}
    </Query>
  )
}

export default EditProfile;

ProfileMutation component

import React, { useRef, useEffect } from 'react';
import { Mutation } from 'react-apollo';
import { UpdateUserProfile } from './operations.graphql';
import "trix/dist/trix.css";
import "./styles.css"

const ProfileMutation = ({ state, profile, setState }) => {
  const trixInput = useRef('');
  let { userId, firstName, lastName, avatar, bio, gender, country } = profile;
  let userID = parseInt(userId);
  // console.log(firstName)

  useEffect(() => {
   trixInput.current.addEventListener('trix-change', (e) => {
    setState({bio: trixInput.current.value})
      console.log(trixInput.current.value)
    })
  },[trixInput])

  return (
    <Mutation mutation={UpdateUserProfile}>
      {(editProfile, { loading }) => (
        <div  className="card bg-light col-md-8 offset-md-2 shadow p-3 mb-5 rounded">
          <article className="card-body">
            <form onSubmit={ e => {
              e.preventDefault();
              editProfile({
                variables: {
                  userId:    userID,
                  firstName: state.firstName,
                  lastName:  state.lastName,
                  bio:       state.bio,
                  avatar:    state.avatar,
                  gender:    state.gender,
                  country:   state.country
                }
              }).then(({ data: { editProfile: { success, errors }  } }) => {
                success ? alert(success) : alert(errors[0]["message"]);
               //TODO: replace alerts with custom message box
              });
            }}
            >
            <div className="form-row mb-3">
              <div className="col">
                <input
                  type="text"
                  name="firstName"
                  placeholder="First name"
                  className="form-control"
                  defaultValue={firstName}
                  onChange={e => setState({firstName: e.currentTarget.value})}
                />
              </div>
              <div className="col">
                <input
                  type="text"
                  name="lastName"
                  placeholder="Last name"
                  className="form-control"
                  defaultValue={lastName}
                  onChange={e => setState({lastName: e.currentTarget.value})}
                />
              </div>
            </div>
            <div className="form-group">
              <label className="">Bio</label>
              <input
                type="hidden"
                defaultValue={bio}
                name="bio"
                id="bio"
              />
              <trix-editor input="bio" ref={trixInput} />
            </div>

            <input type="submit" className="btn btn-primary" value="Update Profile" disabled={loading}/>
            </form>
          </article>
        </div>
      )}
    </Mutation>
  );
}

export default ProfileMutation;

Hope this helps someone! If anyone has a better solution please post it here. Thanks!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.