На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: ElcnU, ANDLL, fatalist
Страницы: (3) [1] 2 3  все  ( Перейти к последнему сообщению )  
> Изучаю React, modern style: ES7, Babel, webpack, bootstrap
    Изучаю React, а вы? :huh:
    Вот набросал примерчик может кому пригодится для изучения
    в нем я максимльно следовал современому стилю программирования на React

    Сам пока до конца не изучил все тонкости React, но думаю заброшу Backbone и перейду на React :D

    /public/index.html:
    ExpandedWrap disabled
      <!DOCTYPE html>
      <html>
       
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>React in action</title>
      </head>
       
      <body>
        <div id="app">
          React in action
        </div>
       
        <script src="/app.js" charset="utf-8"></script>
      </body>
       
      </html>


    /source/app.js:
    ExpandedWrap disabled
      import React from 'react';
      import {render} from 'react-dom';
      import Menu from './menu';
      import data from './data/recipes';
      import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
       
      const App = () =>
        <div className="container">
          <Menu recipes={data}/>
        </div>
       
      render(<App/>, document.getElementById('app'));


    /source/menu.js:
    ExpandedWrap disabled
      import React from 'react';
      import Recipe from './recipe';
       
      const Menu = ({recipes}) =>
        <article>
          <header>
            <h1>Delicious Recipes</h1>
          </header>
          <div className="recipes">
            {recipes.map((recipe, i) =>
              <Recipe key={i} {...recipe}/>)}
          </div>
        </article>;
       
      export default Menu;


    /source/recipe.js:
    ExpandedWrap disabled
      import React from 'react';
      import IngredientsList from './ingredients-list';
      import Instructions from './instructions';
       
      const Recipe = ({name, ingredients, steps}) =>
        <section id={name.toLowerCase().replace(/\s/g, '-')}>
          <h2>{name}</h2>
          <IngredientsList list={ingredients}/>
          <Instructions title="Cooking Instructions" steps={steps}/>
        </section>;
       
      export default Recipe;


    /source/ingredient-list.js:
    ExpandedWrap disabled
      import React from 'react';
      import Ingredient from './ingredient';
       
      const IngredientsList = ({list}) =>
        <ul className="ingredients">
          {list.map((ingredient, key) =>
            <Ingredient key={key} {...ingredient}/>)}
        </ul>;
       
      export default IngredientsList;


    /source/intructions.js:
    ExpandedWrap disabled
      import React from 'react';
       
      const Instructions = ({title, steps}) =>
        <section className="instructions">
          <h3>{title}</h3>
          {steps.map((step, i) =>
            <p key={i}>{step}</p>)}
        </section>;
       
      export default Instructions;


    /source/ingredient.js
    ExpandedWrap disabled
      import React from 'react';
       
      const Ingredient = ({amount, measurement, name}) =>
        <li>
          <span className="amount">{amount}</span>
          <span className="measurement">{measurement}</span>
          <span className="name">{name}</span>
        </li>;
       
      export default Ingredient;



    package.json:
    ExpandedWrap disabled
      {
        "name": "learn-react",
        "version": "1.0.0",
        "description": "",
        "private": true,
        "dependencies": {
          "axios": "^0.18.0",
          "bootstrap": "^4.1.1",
          "express": "^4.16.3",
          "react": "^16.3.2",
          "react-dom": "^16.3.2",
        },
        "devDependencies": {
          "babel-core": "^6.26.0",
          "babel-loader": "^7.1.4",
          "babel-plugin-transform-object-rest-spread": "^6.26.0",
          "babel-preset-env": "^1.6.1",
          "babel-preset-react": "^6.24.1",
          "css-loader": "^0.28.11",
          "nodemon": "^1.17.4",
          "style-loader": "^0.21.0",
          "webpack": "^4.8.3",
          "webpack-cli": "^2.0.15"
        },
        "scripts": {
          "start": "nodemon server.js",
          "build": "webpack --config webpack.config.js"
        },
        "author": "Mudosoft",
        "license": "UNLICENSED"
      }


    webpack.config.js:
    ExpandedWrap disabled
      const path = require('path');
       
      module.exports = {
        mode: 'development',
        entry: './source/app.js',
        output: {
          path: path.resolve(__dirname, 'public'),
          filename: 'app.js',
          sourceMapFilename: 'app.map'
        },
        devtool: '#source-map',
        module: {
          rules: [
            {
              test: /\.js$/,
              use: [
                {
                  loader: 'babel-loader',
                  options: {
                    presets: ['react', 'env'],
                    plugins: [
                      'transform-object-rest-spread'
                    ]
                  }
                }
              ],
              exclude: /(node_modules)/
            },
            {
              test: /\.css$/,
              use: [
                'style-loader',
                'css-loader'
              ]
            }
          ]
        }
      };


    Прикреплённый файлПрикреплённый файлreact_in_action.zip (4,46 Кбайт, скачиваний: 9)

    пс. чтобы все заработало надо выполнить команду npm install, далее npm run build, далее npm start, далее в броузере Chrome набрать localhost:3000 ВСЕ!
    Сообщение отредактировано: Cfon -
      Цитата Cfon
      думаю заброшу Backbone


      что, так много на нём уже сделал, что аж бросать приходится? :whistle:
      свободные и открытые Web-скрипты k313.net закончились...
        Цитата K313 @
        что, так много на нём уже сделал, что аж бросать приходится? :whistle:

        да много всего уже написано на Backbone ~10k строк гавнокода :D
          хотя Backbone ешо на плаву поскольку можно юзать его в связке с React
          надо будет переделать Simple Blog с React+Backbone для практики :D
            Итак продолжаю изучать React!
            добавил два компонента Summary и StarRating.
            в первом показано как в React работать с типами и значениями по умолчанию,
            второй вводит интерактивность в приложение, в связи в этим было введено состояние (state) у компонента App!

            смотрите и учитесь, ну или критикуйте :D

            summary.js:
            ExpandedWrap disabled
              import React, {Component} from 'react';
              import PropTypes from 'prop-types';
               
              class Summary extends Component {
                static propTypes = {
                  ingredientsCount: PropTypes.number,
                  stepsCount: PropTypes.number
                }
                static defaultProps = {
                  ingredientsCount: 0,
                  stepsCount: 0
                }
                render() {
                  const {ingredientsCount, stepsCount} = this.props;
                  return (
                    <div className="summary">
                      <p>{ingredientsCount} ingredients | {stepsCount} steps</p>
                    </div>
                  );
                }
              }
               
              export default Summary;


            star-rating.js:
            ExpandedWrap disabled
              import React from 'react';
              import '../css/star.css'
               
              const Star = ({selected=false, onClick=()=>{}}) =>
                <div className={selected ? 'star selected' : 'star'}
                  onClick={onClick}>
                </div>;
               
              const StarRating = ({starsSelected=0, totalStars=5, onRate=()=>{}}) =>
                <div className="star-rating">
                  {[...Array(totalStars)].map((n, i) =>
                    <Star key={i} selected={i < starsSelected} onClick={()=>onRate(i+1)}/>
                  )}
                  <p>{starsSelected} of {totalStars} stars</p>
                </div>;
               
              export default StarRating;


            recipe.js:
            ExpandedWrap disabled
              import React from 'react'
              import IngredientsList from './ingredients-list'
              import Instructions from './instructions'
              import StarRating from './star-rating'
               
              const Recipe = ({name, ingredients, steps, rating, onRate}) =>
                <section id={name.toLowerCase().replace(/\s/g, '-')}>
                  <h2>{name}</h2>
                  <StarRating starsSelected={rating} onRate={onRate}/>
                  <IngredientsList list={ingredients}/>
                  <Instructions title="Cooking Instructions" steps={steps}/>
                </section>
               
              export default Recipe;


            menu.js:
            ExpandedWrap disabled
              import React from 'react';
              import Recipe from './recipe';
              import Summary from './summary';
               
              const Menu = ({recipes=[], onRate=()=>{}}) => {
                return <article>
                  <header>
                    <h1 className="text-white bg-dark">Delicious Recipes</h1>
                  </header>
                  <div className="recipes">
                    {recipes.map((recipe, i) =>
                      <div key={i}>
                        <Recipe {...recipe} onRate={rating => onRate(recipe.id, rating)}/>
                        <Summary ingredientsCount={recipe.ingredients.length}
                          stepsCount={recipe.steps.length}/>
                        <hr/>
                      </div>)}
                  </div>
                </article>
              }
               
              export default Menu;


            app.js:
            ExpandedWrap disabled
              import React, {Component} from 'react';
              import {render} from 'react-dom';
              import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
              import Menu from './components/menu';
              import data from '../db/recipes';
               
              class App extends Component {
                constructor(props) {
                  super(props);
                  this.state = {
                    recipes: props.data.recipes
                  };
                  this.doRate = this.doRate.bind(this);
                }
                doRate(id, rating) {
                  const {recipes} = this.state;
                  this.setState({
                    recipes: recipes.map(recipe => {
                      return (id !== recipe.id)
                        ? recipe
                        : {
                          ...recipe,
                          rating
                        }
                    })
                  });
                }
                render() {
                  const {recipes} = this.state;
                  return (
                    <div className="container">
                      <Menu recipes={recipes} onRate={this.doRate}/>
                    </div>
                  );
                }
              }
               
              render(<App data={data}/>, document.getElementById('app'));


            Прикреплённый файлПрикреплённый файлreact_in_action_v2.zip (6,9 Кбайт, скачиваний: 5)
            Сообщение отредактировано: Cfon -
              А теперь самое интересное!
              Добавляем форму для добавления рецепта, она будет состоять из трех частей: AddRecipeForm, AddIngredients и AddInstructions.
              Здесь продемонстрировано как получить доступ к элементам DOM через this.refs для сбора информации из формы, также еще раз поработаем с состоянием, но локальным, оно необходимо для временного хранения списка инградиентов и инструкций добавляемого рецепта!
              Вот смотрите мой перл что получилось :D

              add-recipe-form.js:
              ExpandedWrap disabled
                import React, {Component} from 'react';
                import IngredientList from './ingredients-list';
                import AddIngredients from './add-ingredients';
                 
                class AddRecipeForm extends Component {
                  static defaultProps = {
                    onNewRecipe() {}
                  }
                 
                  constructor() {
                    super();
                    this.state = {
                      ingredients: []
                    };
                    this.doSubmitRecipe = this.doSubmitRecipe.bind(this);
                    this.doAddIngredient = this.doAddIngredient.bind(this);
                    this.doClearIngredientList = this.doClearIngredientList.bind(this);
                  }
                 
                  doSubmitRecipe(event) {
                    event.preventDefault();
                    const {_recipeName} = this.refs;
                    const {onNewRecipe} = this.props;
                    const {ingredients} = this.state;
                    onNewRecipe(_recipeName.value, ingredients);
                    this.setState({
                      ingredients: []
                    });
                    _recipeName.value = '';
                    _recipeName.focus();
                  }
                 
                  doAddIngredient(ingredient) {
                    const {ingredients} = this.state;
                    this.setState({
                      ingredients: [
                        ...ingredients,
                        ingredient
                      ]
                    });
                  }
                 
                  doClearIngredientList() {
                    this.setState({
                      ingredients: []
                    });
                  }
                 
                  render() {
                    const {ingredients} = this.state;
                    return (
                      <div>
                        <h3>Add Recipe</h3>
                        <form onSubmit={this.doSubmitRecipe}>
                          <input className="form-control" ref="_recipeName" type="text" placeholder="Recipe name" required/>
                          <div className="card mt-2">
                            <div className="card-body">
                              {
                                (ingredients.length !== 0)
                                  ? <IngredientList list={ingredients}/>
                                  : <p>No ingredients</p>
                              }
                              <AddIngredients onNewIngredient={this.doAddIngredient}
                                onClearIngredientList={this.doClearIngredientList}/>
                            </div>
                          </div>
                          {/* TODO: add AddInstructions Element */}
                          <button className="btn btn-primary mt-2">Add Recipe</button>
                        </form>
                      </div>
                    );
                  }
                }
                 
                export default AddRecipeForm;


              add-ingredients.js:
              ExpandedWrap disabled
                import React, {Component} from 'react';
                 
                class AddIngredients extends Component {
                  static defaultProps = {
                    onNewIngredient(ingredient) {},
                    onClearIngredientList() {}
                  }
                 
                  constructor() {
                    super();
                    this.doAddIngredient = this.doAddIngredient.bind(this);
                    this.doClearIngredientList = this.doClearIngredientList.bind(this);
                  }
                 
                  doAddIngredient(event) {
                    event.preventDefault();
                    const {_ingredientName, _amount, _measurement} = this.refs;
                    const {onNewIngredient} = this.props;
                    onNewIngredient({
                      name: _ingredientName.value,
                      amount: _amount.value,
                      measurement: _measurement.value
                    });
                    this.clearInputs();
                  }
                 
                  doClearIngredientList(event) {
                    event.preventDefault();
                    const {onClearIngredientList} = this.props;
                    onClearIngredientList();
                    this.clearInputs();
                  }
                 
                  clearInputs() {
                    const {_ingredientName, _amount, _measurement} = this.refs;
                    _ingredientName.value = '';
                    _amount.value = '';
                    _measurement.value = '';
                    _amount.focus();
                  }
                 
                  render() {
                    return (
                      <div className="ingredient-form">
                        <input className="form-control" ref="_amount" type="text" placeholder="Amount"/>
                        <input className="form-control" ref="_measurement" type="text" placeholder="Measurement"/>
                        <input className="form-control" ref="_ingredientName" type="text" placeholder="Ingredient name"/>
                        <div className="mt-2">
                          <button className="btn btn-secondary mr-2" onClick={this.doAddIngredient}>Add Ingredient</button>
                          <button className="btn btn-secondary mr-2" onClick={this.doClearIngredientList}>Clear Ingredient List</button>
                        </div>
                      </div>
                    );
                  }
                }
                 
                export default AddIngredients;


              app.js (с внесеными изменениями):
              ExpandedWrap disabled
                import React, {Component} from 'react';
                import {render} from 'react-dom';
                import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
                import Menu from './components/menu';
                import data from '../db/recipes';
                import AddRecipeForm from './components/add-recipe-form';
                import {v4} from 'uuid';
                 
                class App extends Component {
                 
                  constructor(props) {
                    super(props);
                    this.state = {
                      recipes: props.data.recipes
                    };
                    this.doRate = this.doRate.bind(this);
                    this.doAddRecipe = this.doAddRecipe.bind(this);
                  }
                 
                  doRate(id, rating) {
                    const {recipes} = this.state;
                    this.setState({
                      recipes: recipes.map(recipe => {
                        return (id !== recipe.id)
                          ? recipe
                          : {
                            ...recipe,
                            rating
                          }
                      })
                    });
                  }
                 
                  doAddRecipe(name, ingredients) {
                    const {recipes} = this.state;
                    this.setState({
                      recipes: [
                        ...recipes,
                        {
                          id: v4(),
                          name,
                          ingredients,
                          steps: [],
                          rating: 0
                        }
                      ]
                    });
                  }
                 
                  render() {
                    const {recipes} = this.state;
                    return (
                      <div className="container">
                        <Menu recipes={recipes} onRate={this.doRate}/>
                        <AddRecipeForm onNewRecipe={this.doAddRecipe}/>
                      </div>
                    );
                  }
                }
                 
                render(<App data={data}/>, document.getElementById('app'));

              Прикреплённый файлПрикреплённый файлreact_in_action_v3.zip (8,58 Кбайт, скачиваний: 5)

              Нет элемента AddInstructions? Предлагаю самостоятельно добавить его, как домашнее задание :D
              Ну а если у вас не получиться, то я позже добавлю :jokingly:

              пс. возможно лучше состояние перенести из AddRecipeForm в AddIngredients? тут надо подумать как лучше :blush:
              Сообщение отредактировано: Cfon -
                Эх, ещё с год назад пытался вразумить на счёт ES6+, донести что прототипы мертвы... А сегодня ты уже на реакте фигачишь :-?

                Куда катится мир.
                user posted image
                  Цитата Serafim @
                  Эх, ещё с год назад пытался вразумить на счёт ES6+, донести что прототипы мертвы... А сегодня ты уже на реакте фигачишь :-?

                  Куда катится мир.

                  ну без прототипов знание JS не будет не полным, поэтому я все правильно изучал последовательно и планомерно, скоро перейду на Angular :D
                    Цитата Cfon @
                    Нет элемента AddInstructions? Предлагаю самостоятельно добавить его, как домашнее задание :D

                    Ответ на домашнее задание:
                    Вместо класса юзал функцию, в реакте такой стиль написания кода поощряется и если вы будете так писать вас возмут в Facebook :D
                    собственно instruction-form.js
                    ExpandedWrap disabled
                      import React from 'react';
                       
                      const InstructionForm = ({onNewInstruction=f=>f, onClear=f=>f}) => {
                        let _step;
                        const add = (e) => {
                          e.preventDefault();
                          onNewInstruction(_step.value);
                          clearInputs();
                        }
                        const clear = (e) => {
                          e.preventDefault();
                          onClear();
                        }
                        const clearInputs = () => {
                          _step.value = '';
                        }
                        return (
                          <div className="instruction-form">
                            <input className="form-control" ref={i => _step = i} type="text" placeholder="Step"/>
                            <div className="mt-2">
                              <button className="btn btn-secondary mr-2" onClick={add}>Add Instruction</button>
                              <button className="btn btn-secondary mr-2" onClick={clear}>Clear Instruction List</button>
                            </div>
                          </div>
                        );
                      };
                       
                      export default InstructionForm;


                    изменения в recipe-form.js:
                    ExpandedWrap disabled
                      import React, {Component} from 'react';
                      import IngredientList from './ingredients-list';
                      import IngredientForm from './ingredient-form';
                      import Instructions from './instructions';
                      import InstructionForm from './instruction-form';
                       
                      class RecipeForm extends Component {
                        static defaultProps = {
                          onNewRecipe() {}
                        }
                       
                        constructor() {
                          super();
                          this.state = {
                            ingredients: [],
                            instructions: [] //<--
                          };
                          this.submitRecipe = this.submitRecipe.bind(this);
                          this.addIngredient = this.addIngredient.bind(this);
                          this.clearIngredientList = this.clearIngredientList.bind(this);
                          
                          this.addInstruction = this.addInstruction.bind(this); //<--
                          this.clearInstructions = this.clearInstructions.bind(this); //<--
                        }
                       
                        submitRecipe(event) {
                          event.preventDefault();
                          const {_recipeName} = this.refs;
                          const {onNewRecipe} = this.props;
                          const {ingredients, instructions} = this.state;
                                               // ^^^
                          onNewRecipe(_recipeName.value, ingredients, instructions);
                                                                       // ^^^
                          this.clearIngredientList();
                          this.clearInstructions(); //<--
                          _recipeName.value = '';
                          _recipeName.focus();
                        }
                       
                        addIngredient(ingredient) {
                          const {ingredients} = this.state;
                          this.setState({
                            ingredients: [
                              ...ingredients,
                              ingredient
                            ]
                          });
                        }
                       
                        clearIngredientList() {
                          this.setState({
                            ingredients: []
                          });
                        }
                       
                        addInstruction(step) { //<--
                          const {instructions} = this.state;
                          this.setState({
                            instructions: [
                              ...instructions,
                              step
                            ]
                          });
                        }
                       
                        clearInstructions() { //<--
                          this.setState({
                            instructions: []
                          });
                        }
                       
                        render() {
                          const {ingredients, instructions} = this.state;
                          return (
                            <div>
                              <h3>Add Recipe</h3>
                              <form onSubmit={this.submitRecipe}>
                                <input className="form-control" ref="_recipeName" type="text" placeholder="Recipe name" required/>
                                <div className="card mt-2">
                                  <div className="card-body">
                                    {
                                      (ingredients.length !== 0)
                                        ? <IngredientList list={ingredients}/>
                                        : <p>No ingredients</p>
                                    }
                                    <IngredientForm onNewIngredient={this.addIngredient}
                                      onClear={this.clearIngredientList}/>
                                  </div>
                                </div>
                                {/* AND HERE */}
                                <div className="card mt-2">
                                  <div className="card-body">
                                    {
                                      (instructions.length !== 0)
                                        ? <Instructions steps={instructions}/>
                                        : <p>No instructions</p>
                                    }
                                    <InstructionForm onNewInstruction={this.addInstruction}
                                      onClear={this.clearInstructions}/>
                                  </div>
                                </div>
                                <button className="btn btn-primary mt-2">Add Recipe</button>
                              </form>
                            </div>
                          );
                        }
                      }
                       
                      export default RecipeForm;


                    изменения в app.js:
                    ExpandedWrap disabled
                      import React, {Component} from 'react';
                      import {render} from 'react-dom';
                      import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
                      import Menu from './components/menu';
                      import data from '../db/recipes';
                      import RecipeForm from './components/recipe-form';
                      import {v4} from 'uuid';
                       
                      class App extends Component {
                       
                        constructor(props) {
                          super(props);
                          this.state = {
                            recipes: props.data.recipes
                          };
                          this.doRate = this.doRate.bind(this);
                          this.addRecipe = this.addRecipe.bind(this);
                        }
                       
                        doRate(id, rating) {
                          const {recipes} = this.state;
                          this.setState({
                            recipes: recipes.map(recipe => {
                              return (id !== recipe.id)
                                ? recipe
                                : {
                                  ...recipe,
                                  rating
                                }
                            })
                          });
                        }
                       
                        addRecipe(name, ingredients, steps) {
                                                   // ^^^
                          const {recipes} = this.state;
                          const recipe = {
                            id: v4(),
                            name,
                            ingredients,
                            steps, //<--
                            rating: 0
                          };
                          this.setState({
                            recipes: [
                              ...recipes,
                              recipe
                            ]
                          });
                        }
                       
                        render() {
                          const {recipes} = this.state;
                          return (
                            <div className="container">
                              <Menu recipes={recipes} onRate={this.doRate}/>
                              <RecipeForm onNewRecipe={this.addRecipe}/>
                            </div>
                          );
                        }
                      }
                       
                      render(<App data={data}/>, document.getElementById('app'));


                    Прикреплённый файлПрикреплённый файлreact_in_action_v3_1.zip (9,43 Кбайт, скачиваний: 4)

                    Пока все! Продолжение следует...
                    Сообщение отредактировано: Cfon -
                      Так продолжаю изучать React и сегодня я разбираюсь c жизненным циклом обновления компоненты (updating component lifecycle)
                      а именно с методом componentWillReceiveProps, который как мне показалось является самым сложным в понимании его использования. В качестве примера решил взять уже избитый мною класс Person, но переложеный на React
                      Короче вот пример:
                      person.js
                      ExpandedWrap disabled
                        class Person extends Component {
                          constructor() {
                            super();
                            this.state = {
                              isYoung: false
                            };
                          }
                         
                          // А ВОТ И ОН!
                          componentWillReceiveProps(nextProps) {
                            this.setState({
                              isYoung: nextProps.age < 20
                            });
                          }
                         
                          render() {
                            const {name, isSelected, onClick} = this.props;
                            const {isYoung} = this.state;
                            return (
                              <li className={isSelected ? (isYoung ? 'young-selected' : 'selected') : ''} onClick={onClick}>
                                {name}
                              </li>
                            );
                          }
                        }

                      persons.js
                      ExpandedWrap disabled
                        const Persons = ({persons=[], onSelect=f=>f}) => (
                          <ul className="persons-list">
                            {persons.map((person, i) =>
                              <Person key={i} {...person} onClick={() => onSelect(i)}/>
                            )}
                          </ul>
                        );

                      person-form.js
                      ExpandedWrap disabled
                        const PersonForm = ({onSubmit=f=>f}) => {
                          let nameInput, ageInput;
                         
                          const submit = e => {
                            e.preventDefault();
                            onSubmit(nameInput.value, ageInput.value);
                            clearInputs();
                          };
                         
                          const clearInputs = () => {
                            nameInput.value = '';
                            ageInput.value = '';
                            nameInput.focus();
                          };
                         
                          return (
                            <form onSubmit={submit}>
                              <input type="text" ref={i => nameInput = i} placeholder="Name"/>
                              <input type="text" ref={i => ageInput = i} placeholder="Age"/>
                              <button>Submit</button>
                            </form>
                          );
                        };

                      app.js
                      ExpandedWrap disabled
                        class App extends Component {
                          constructor() {
                            super();
                            this.state = {
                              persons: []
                            };
                            this.addPerson = this.addPerson.bind(this);
                            this.selectPerson = this.selectPerson.bind(this);
                          }
                         
                          addPerson(name, age) {
                            const {persons} = this.state;
                            const person = {
                              name,
                              age,
                              isSelected: false
                            };
                            this.setState({
                              persons: [
                                ...persons,
                                person
                              ]
                            });
                          }
                         
                          selectPerson(index) {
                            const {persons} = this.state;
                            this.setState({
                              persons: persons.map((person, i) => {
                                return (index !== i)
                                  ? person
                                  : {
                                    ...person,
                                    isSelected: !person.isSelected
                                  }
                              })
                            });
                          }
                         
                          render() {
                            const {persons} = this.state;
                            return (
                              <div>
                                <PersonForm onSubmit={this.addPerson}/>
                                <Persons persons={persons} onSelect={this.selectPerson}/>
                              </div>
                            );
                          }
                        }
                         
                        render(
                          <App />,
                          document.getElementById('app')
                        );

                      Объяснение этого кода я отложу не потом, а пока просто изучите его, возможно что вы и сами поймете наконец как юзать componentWillReceiveProps :D
                      Если вкраце то его юзат как правило для обновления состояния дочернего компонента при изменении его свойств родительским компонентом :blink: :lool:
                      Сообщение отредактировано: Cfon -
                        Меня многие спрашивают а как перенести данные на сервер?! :blink:
                        Отвечаю например постаринке юзать AJAX и REST API :D
                        В качестве обертки AJAX можно юзать пакеты isomorphic-fetch или axios. Или тот же jQuery :D
                        утсанавливаем их командой yarn add isomorphic-fetch или yarn add axios
                        Хотя в последней версии хрома isomorphic-fetch уже поддержвается так что можно не устанавливать.
                        Также в примере показано использование метода жизненного цикла componentWillMount
                        Вот код изменения в коде сервера и клиента, в качестве БД взял NoSQL Bourne, при желании можно заменить на MongoDB:

                        server.js
                        ExpandedWrap disabled
                          import express from 'express';
                          import logger from 'morgan';
                          import Bourne from 'bourne';
                           
                          const app = express();
                          const recipes = new Bourne('db/recipes.json');
                           
                          app.use(logger('dev'));
                          app.use(express.static('public'));
                           
                          app.get('/', (req, res) => {
                            res.sendFile('index.html');
                          });
                           
                          // REST API
                          app.get('/recipes.json', (req, res) => {
                            recipes.find((err, results) => {
                              res.json(results);
                            });
                          });
                           
                          app.listen(3000, () => console.log(`Application running at 'http://localhost:3000'`));


                        app.js
                        ExpandedWrap disabled
                          import React, {Component} from 'react';
                          import {render} from 'react-dom';
                          import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
                          import Menu from './components/menu';
                          import RecipeForm from './components/recipe-form';
                          import {v4} from 'uuid';
                          import fetch from 'isomorphic-fetch';
                          // import axios from 'axios';
                           
                          class App extends Component {
                           
                            constructor(props) {
                              super(props);
                              this.state = {
                                recipes: []
                              };
                              this.doRate = this.doRate.bind(this);
                              this.addRecipe = this.addRecipe.bind(this);
                            }
                           
                            // Получаем данные с сервера
                            componentWillMount() {
                              fetch(`/recipes.json`)
                                .then(res => res.json())
                                .then(recipes => this.setState({recipes}))
                                .catch(err => console.error(err));    
                            }
                           
                            doRate(id, rating) {
                              const {recipes} = this.state;
                              this.setState({
                                recipes: recipes.map(recipe => {
                                  return (id !== recipe.id)
                                    ? recipe
                                    : {
                                      ...recipe,
                                      rating
                                    }
                                })
                              });
                            }
                           
                            addRecipe(name, ingredients, steps) {
                              const {recipes} = this.state;
                              const recipe = {
                                id: v4(),
                                name,
                                ingredients,
                                steps,
                                rating: 0
                              };
                              this.setState({
                                recipes: [
                                  ...recipes,
                                  recipe
                                ]
                              });
                            }
                           
                            render() {
                              const {recipes} = this.state;
                              return (
                                <div className="container">
                                  <Menu recipes={recipes} onRate={this.doRate}/>
                                  <RecipeForm onNewRecipe={this.addRecipe}/>
                                </div>
                              );
                            }
                          }
                           
                          render(<App />, document.getElementById('app'));


                        Прикреплённый файлПрикреплённый файлreact_in_action_v3_2.zip (9,63 Кбайт, скачиваний: 3)
                        Сообщение отредактировано: Cfon -
                          Цитата Cfon @
                          Отвечаю например постаринке юзать AJAX и REST API


                          REST API REST IN PEACE :whistle:
                          user posted image
                            Цитата Serafim @
                            REST API REST IN PEACE :whistle:

                            Hail to the GraphQL? :D
                            Подпись выключена.
                              Цитата Астарот @
                              Hail to the GraphQL?

                              О, а вот ты шаришь в трендах этого грешного мира, а притворялся джавистом. :D
                              user posted image
                                Цитата Serafim @
                                О, а вот ты шаришь в трендах этого грешного мира, а притворялся джавистом. :D

                                Так те же яйца, только в профиль :D
                                Подпись выключена.
                                1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) [1] 2 3  все


                                Рейтинг@Mail.ru
                                [ Script Execution time: 0,2400 ]   [ 22 queries used ]   [ Generated: 20.07.18, 01:18 GMT ]