最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React access and update variable outside of render - Stack Overflow

programmeradmin0浏览0评论

I'm currently learning React and am following this guy Youtube Videos.

However, they are outdated and it's difficult to get along with the old codes. I already tried some Stackoverflow and Google solutions, but they didn't help.

Right now am I struggling on how I can access my variable todo which I declared inside render() and update it with a my function handleDelete outside of render()?

My goal is to delete the item i clicked on.

I already tried to set my variable inside constructor() but then it wasn't possible to give it the value of this.props.todos.

My code:

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {

  handleDelete(item){
    let updatedTodos = this.props.todos;
    updatedTodos = updatedTodos.filter((val,index) => {
      return item !== val;
    })
    todos = updatedTodos;
  };

  render() {
    //Add all this.props items
    let todos = this.props.todos;
    todos = todos.map((item, index) => {

      return (
      <li>
        <div className="todo-item">
          <span className="item-name">{item}</span>
          <span className="item-remove" onClick={this.handleDelete.bind(this, item)}> x </span>
        </div>
      </li>);
    });


    return (<React.Fragment>{todos}</React.Fragment>)
  };
}

(This code is later exported to index.js where it is transpiled with Babel)

Thanks for your time taken!

Update:

Here is index.js:

import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        todos: ["clean up", "walk doggo", "take nap"]
      };
    }
    render() {

      return (<div>

        <h1>The todo list:</h1>
        <ul>
          <TodoItem todos={this.state.todos}/>
        </ul>
      </div>);
    }

  }

  ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));

I'm currently learning React and am following this guy Youtube Videos.

However, they are outdated and it's difficult to get along with the old codes. I already tried some Stackoverflow and Google solutions, but they didn't help.

Right now am I struggling on how I can access my variable todo which I declared inside render() and update it with a my function handleDelete outside of render()?

My goal is to delete the item i clicked on.

I already tried to set my variable inside constructor() but then it wasn't possible to give it the value of this.props.todos.

My code:

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {

  handleDelete(item){
    let updatedTodos = this.props.todos;
    updatedTodos = updatedTodos.filter((val,index) => {
      return item !== val;
    })
    todos = updatedTodos;
  };

  render() {
    //Add all this.props items
    let todos = this.props.todos;
    todos = todos.map((item, index) => {

      return (
      <li>
        <div className="todo-item">
          <span className="item-name">{item}</span>
          <span className="item-remove" onClick={this.handleDelete.bind(this, item)}> x </span>
        </div>
      </li>);
    });


    return (<React.Fragment>{todos}</React.Fragment>)
  };
}

(This code is later exported to index.js where it is transpiled with Babel)

Thanks for your time taken!

Update:

Here is index.js:

import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        todos: ["clean up", "walk doggo", "take nap"]
      };
    }
    render() {

      return (<div>

        <h1>The todo list:</h1>
        <ul>
          <TodoItem todos={this.state.todos}/>
        </ul>
      </div>);
    }

  }

  ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));
Share Improve this question edited Jul 31, 2018 at 13:45 Max Frenter asked Jul 31, 2018 at 13:18 Max FrenterMax Frenter 421 silver badge10 bronze badges 10
  • You are getting todos as a prop so it should be in a parent ponent's state. Like todos you need a delete handler from your parent ponent as a prop. Then you will use this function in your handleDelete function and pass the todos. Can we see your parent ponent as well? – devserkan Commented Jul 31, 2018 at 13:23
  • your second return statment would never fire – Shubham Agarwal Bhewanewala Commented Jul 31, 2018 at 13:29
  • @ShubhamAgarwalBhewanewala, second return belongs to render. First one is for map. So, actually it should work. – devserkan Commented Jul 31, 2018 at 13:33
  • Ah.. what is an item?? an object or string or number – Shubham Agarwal Bhewanewala Commented Jul 31, 2018 at 13:36
  • 1 I suggest that you learn about variable scope in JavaScript. Also learn about state management in ReactJS. – Code-Apprentice Commented Jul 31, 2018 at 14:09
 |  Show 5 more ments

3 Answers 3

Reset to default 3

TodoComponent

import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        todos: ["clean up", "walk doggo", "take nap"]
      };
    }
    handleDelete(item){
        let todos = this.state.todos;
        todos= todos.filter((todo) => todo !== item);
        this.setState((prevState) => ({
            todos: todos
        }));
    };
    render() {

      return (<div>

        <h1>The todo list:</h1>
        <ul>
          <TodoItem todos={this.state.todos} handleDelete={this.handleDelete}/>
        </ul>
      </div>);
    }

  }

  ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));

Todo Item

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {
    render() {
        return ( 
            this.props.todos.map((item) => {
            return (
                <li>
                    <div className="todo-item">
                    <span className="item-name">{item}</span>
                    <span className="item-remove" onClick={() => this.props.handleDelete(item)}> x </span>
                    </div>
                </li>
            )
        }))
    }
}

Your code is having the problem in TodoItem that you are trying to delete items in TodoItem where you do not have access to state. And moreover If you do some actions in ponent and you want to get the change reflected the your ponents must re render. And this is possible when your state is changed. And ponent related to corresponding changes will re render itself

I have not tested it so there might be some typos but you have to do it like this

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {

handleDelete(item){
   this.props.updateTodos(item)
};

render() {
//Add all this.props items
 let todos = this.props.todos;
 todos = todos.map((item, index) => {

  return (
  <li>
    <div className="todo-item">
      <span className="item-name">{item}</span>
      <span className="item-remove" onClick={this.handleDelete.bind(this, item)}> x </span>
    </div>
  </li>);
 });


 return (<React.Fragment>{todos}</React.Fragment>)
};
}



import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React.Component {
constructor(props) {
  super(props);
  this.state = {
    todos: ["clean up", "walk doggo", "take nap"]
  };
  this.updateTodos =this.updateTodos.bind(this);
}
 updateTodos(item){
   this.setState({todos :this.state.todos.filter((val,index) => {
     return item !== val;
   })})
}
render() {

  return (<div>

    <h1>The todo list:</h1>
    <ul>
      <TodoItem todos={this.state.todos} updateTodos ={this.updateTodos}/>
    </ul>
  </div>);
}

}

 ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));

I'm suggesting a different approach for you. There are some issues you need to think better. First of all, I suggest keeping your todos as objects and let have them id and text properties.

Second, you have a separate ponent but you are passing to it whole todos. Instead of that, map your todos and then pass each todo to your ponent. In this way your management over everything will be easier.

For your situation, you need a delete handler to pass your TodoItem, then by using this handler you will do the action.

Lastly, your TodoItem does not need to be a class ponent, so I've changed it.

Here is a working example. I've changed your code according to my suggestions.

class Todos extends React.Component {
  state = {
    todos: [
      { id: 1, text: "foo" },
      { id: 2, text: "bar" },
      { id: 3, text: "baz" },
    ]
  }

  deleteTodo = ( todo ) => {
    const newTodos = this.state.todos.filter( el => el.id !== todo.id );
    this.setState({ todos: newTodos });
  }

  render() {
    const { todos } = this.state;
    return (
      <div>
        <ul>
        {
          todos.map( todo => <TodoItem key={todo.id} todo={todo} deleteTodo={this.deleteTodo} /> )
        }
        </ul>
      </div>
    )
  }
}

const TodoItem = props => {
  const handleDelete = () => props.deleteTodo(props.todo);

  return (
    <li onClick={handleDelete}>{props.todo.text} x</li>
  )
};

ReactDOM.render(<Todos />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Also, last night I wrote a small example for another question. But it got bigger and bigger and I did not post it. But here is a small, simple Todo example. Of course there must be some improvements but you can examine it as an example.

https://codesandbox.io/s/01v3kmp9vv

Edit

If you don't want to use class-fields and install another Babel plugin, just change the related part with this:

class Todos extends React.Component {
  consturctor( props ) {
      super( props );
      this.state = {
          todos: [
          { id: 1, text: "foo" },
          { id: 2, text: "bar" },
          { id: 3, text: "baz" },
        ],
  }
}
....rest of the code
发布评论

评论列表(0)

  1. 暂无评论