Issue with Changing, Updating List including Token

Hey guys,
When it’s about user accounts and cookies, React seems to be a bit harder to master than using pure Javascript.

Here’s the case: my app allows a user to register and log in. When signing in every user will get a cookie set for the individual authorization code and the user’s id. The user id will be used in some API calls through fetch (I don’t use Axios in this project). I just replace a placeholder I used for my project when building it to make it ready for a serious test. So instead of, let’s say “user_id: 1, text_input…” I use “user_id: props.user_id” or so.

The problem that occurs is that everything seems to work occasionally. I’d apply a case from one part of my project, the “skills”-category. There are three major interactions.

  • Search and add a skill to a user’s skill list
  • List all current skills of a user
  • Remove a skill from the user’s skill list

I can say that the functions worked well until I started implementing the ID. I’d usually say there’s a simple problem to fix. But the functions behave inconsistently and strange.

Here’s an example.
I click on remove a skill item and it’s gone. I do it again and it remains. No change happens until I add a skill from the search list. But this mostly changes the list by removing, not adding, sometimes it does.

On another part of the app I have a similar problem, but there it suddenly shows a JSON-error.

The code I use for the skill part is:

skills.js

import React from "react";
import './../App.css';
import auth from './../auth'

import SkillList from "../components/skillsearch/skills.list";
import FindSkills from '../components/skillsearch/skills.find';


class Skills extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            nation: "",
            nations: [],
            countries: [],
            teams: [],
            items: [],
            selectCountry: [],
            selectedCountry: "",
            selectedDivision: "",
            isLoaded: false,
            entityURL: "",
            entityName: "",
            curWorkHere: false,
            error: null,
            inputValue: "",

            lastDirection: "",
            lastSkillID: "",
            userID:"",
        };
    }

    componentWillMount(){
      this.setState({userID:auth.getCookie('gscover')})
    }

    handleChange = (e) => {
        this.setState({ selectedDivision: e.target.value })
        console.log(this.state)
        console.log(e.target.value)
    }

    textChange = inputValue => {
        this.setState({ inputValue: inputValue.value });
        console.log(inputValue.value);
    };

    handleLangChange = () => {
        var lang = this.dropdown.value;
        this.props.onSelectLanguage(lang);            
    }

/*     handleMyChange = (newValue) => {
        this.props.setState({ inputValue: newValue });
      } */
    
    manageSkill = (direction, skill_id,user_skills_id) => {
        let entityweb = this.state.entityURL;
        var user_id = this.state.userID;
        var direction_string;
        console.log(direction+" "+skill_id+" "+user_skills_id)
        if(direction==1)
        {
          direction_string = "add";
        }
        if(direction==0)
        {
          direction_string = "delete";
        }
        console.log(direction+" "+direction_string)
        var skillJSONObject = JSON.stringify({"user_id":user_id,"skill_id":skill_id,"user_skills_id":user_skills_id});
        fetch("https://myapi.com/v1/skills/user/"+direction_string, {
          method: 'POST',
          body: skillJSONObject,
          headers: {
            'Authorization': this.props.code
          }})
          .then(response => response.json())
          .catch(error => {
            console.error('Error:', error);
          });
        console.log(this.state);
        this.setState({ inputValue: skill_id, lastDirection:direction,lastSkillID:skill_id });
      };


    handleMyChange = (temperature) => {
        this.setState({inputValue: temperature});  
        console.log(temperature)
        this.manageSkill(1,temperature)
    }

    refresh = () => {

    }

    render() {
        return <div>


            <div className="max-w-2xl mx-auto px-1 pb-8 sm:px-6 lg:px-8 bg-gray-200">
            <div>
                
                <FindSkills value={this.state.inputValue} onTemperatureChange={this.handleMyChange} code={this.props.code} user={this.state.userID}/>                
            </div>                


                <SkillList manageSkill = {this.manageSkill} refresh={{direction:this.state.lastDirection,skillid:this.state.lastSkillID}} code={this.props.code}  user={this.state.userID}/>


            </div>
        </div>
    }
}
export default Skills;

skills.find.js

import React from "react";
import AsyncSelect from 'react-select';

class FindSkills extends React.Component {
    constructor(props) {
        super(props);
        this.handleMyChange = this.handleMyChange.bind(this);
        this.state = {
          error: null,
          isLoaded: false,
          selectedCountry: null,
          values: [],
          inputValue: "",
        };
      }

    componentDidMount() {
        fetch('https://myapi.com/v2/admin/listskills')
            .then(res => res.json())
            .then(res => this.setState({
                values: res.data
            }))
            .catch(error => console.log(error))
    }

    textChange = inputValue => {
        this.setState({ inputValue: inputValue.value });
        console.log(inputValue.value);
    };

    handleMyChange = inputValue => {
      // Here, we invoke the callback with the new value
      this.props.onTemperatureChange(inputValue.value);
    }

    render() {
        let option = []
        if (this.state.values.length > 0) {
          this.state.values.forEach(role => {
            let roleDate = {}
            roleDate.value = role.skill_id
            roleDate.label = role.name
            option.push(roleDate)
          })
        }        
        return (
            <div>
                <AsyncSelect options={option} value={this.props.value} onChange={this.handleMyChange}/>
            </div>
        )
    }
}

export default FindSkills;

skills.list.js

import React from "react";
import auth from "./../../auth"

class SkillList extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            myinput: "hello",
            skill_items: [],
            lastDirection: "",
            lastSkillID:"",
            isLoaded: false,
            error: null,
            userID:'',
        };
    }

    async componentWillMount(){
        this.setState({userID:auth.getCookie('gscover')})
      }

    getuserSkills = (e) => {
        var user_id = this.props.user;
        var skillJSONObject = JSON.stringify({ "user_id":user_id, "withvalue": 1 });

        fetch("https://myapi.com/v1/skills/all/user", {
            method: 'POST',
            body: skillJSONObject,
            headers: {
                'Authorization': this.props.code
            }
        })
            .then(response => response.json())
            //.then(json => json.data.map(skill => skill.name))
            .then(data => {
                //console.log(data.data[0].name)
                if (data.hasOwnProperty("response")) {
                    console.log(data["response"]["data"]);
                    this.setState({
                        isLoaded: true,
                        skill_items: data["response"]["data"]
                    });
                }
                else {
                    console.log(data);

                }
            }).catch(error => {
                console.error('Error:', error);
            });
        console.log(this.state);
    };

    componentDidMount() {
        this.getuserSkills();

        //this.createCV();
    }

    componentWillReceiveProps(props) {
        const { direction, skillid } = this.props;
        if (this.state.lastDirection !== direction && this.state.lastSkillID !== skillid) {
            this.getuserSkills();
        }
      }
 


    render() {
        const { error, isLoaded, skill_items } = this.state;
        if (error) {
            return <div>Error: {error.message}</div>;
        } else if (!isLoaded) {
            return <div>Loading...</div>;
        } else {
            return (
                
                <div className="pt-5 px-1 md:px-0">
                    {skill_items.map(item => (
                        <div>
                            <div class="flex justify-center bg-gray-100 mb-2">
                                <div class="w-full max-w-lg pt-4">

                                    <div class="flex">
                                        <a className="my-auto"><p class="text-gray-900 w-20"><a class="text-3xl font-semibold">{item.skill_scoring==null ? "--" : item.skill_scoring*10}</a> <a className={item.scoring_change > 0 ?  "text-green-400 font-bold" :  item.scoring_change < 0 ? "text-red-400 font-bold" : "text-blue-400 font-bold"}>{item.scoring_change > 0 ?  "↑" : item.scoring_change < 0 ? "↓" : ""} {item.scoring_change != null ?  "("+item.scoring_change*10+")" : ""}</a></p></a>
                                        <div class="flex-1 pl-4">
                                            <p class="text-gray-500">{item.category}</p>
                                            <div class="flex items-baseline space-x-4">
                                                <h2 class="text-2xl font-semibold">
                                                    {item.name}
                                                </h2>
                                            </div>
                                        </div>
                                        <div class="flex-no-shrink">
                                            <p><button class="remBtn p-1 ml-2 border-2 rounded text-red-400 border-red-400 hover:text-white hover:bg-red-400">&#120;<a className="remText" onClick= { () => this.props.manageSkill(0,item.skill_id,item.user_skills_id)}> Remove</a></button></p>
                                        </div>

                                    </div>
                                    <div class="flex p-1 border-t border-gray-300 text-gray-700">
                                        <div class="flex-1 mx-auto inline-flex items-center">
                                            <p className="mx-auto"><span class="text-gray-900 font-bold">{item.ratings!=null ? item.ratings : "0"}</span> Grades<span className="text-gray-400 text-sm"> last 30d</span></p>
                                        </div>
                                        <div class="flex-1 mx-auto inline-flex items-center text-center hover:text-blue-400 hover:bg-blue-100">
                                            <p className="mx-auto"><a href={"rateme/user/"+item.category}>Share</a></p>
                                        </div>
                                    </div>

                                </div>
                            </div>
                        </div>
                    ))}
                </div>
            )
        }
    }}

    export default SkillList;

Because the function is requested from time to time here’s the getCookie-function from auth.js

    getCookie(cname) {
      var name = cname + "=";
      var ca = document.cookie.split(';');
      for(var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
          c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
          return c.substring(name.length, c.length);
        }
      }
      return "";
    }

Maybe I make a simple mistake or it’s not best practice. But the strange behavior of the functions mentioned above is confusing me, so I guess there’s a speed or storing issue? Maybe you can give me a hint to the solution.

The problem has been solved after finding a good example on how to do this. The problem was not in my API calls but the place where I handled the entries. Doing this in a parent element was the solution.
I highly recommend this tutorial.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.