<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          如何優雅的設計 React 組件

          時間:?2017-11-13閱讀:?801標簽:?react作者:?曉冬

          作者:曉冬
          本文原創,轉載請注明作者及出處

          如今的 Web 前端已被 React、Vue 和 Angular 三分天下,一統江山十幾年的 jQuery 顯然已經很難滿足現在的開發模式。那么,為什么大家會覺得 jQuery “過時了”呢?一來,文章《No JQuery! 原生 JavaScript 操作 DOM》就直截了當的告訴你,現在用原生 JavaScript 可以非常方便的操作 DOM 了。其次,jQuery 的便利性是建立在有一個基礎 DOM 結構的前提下的,看上去是符合了樣式、行為和結構分離,但其實 DOM 結構和 JavaScript 的代碼邏輯是耦合的,你的開發思路會不斷的在 DOM 結構和 JavaScript 之間來回切換。

          盡管現在的 jQuery 已不再那么流行,但 jQuery 的設計思想還是非常值得致敬和學習的,特別是 jQuery 的插件化。如果大家開發過 jQuery 插件的話,想必都會知道,一個插件要足夠靈活,需要有細顆粒度的參數化設計。一個靈活好用的 React 組件跟 jQuery 插件一樣,都離不開合理的屬性化(props)設計,但 React 組件的拆分和組合比起 jQuery 插件來說還是簡單的令人發指。

          So! 接下來我們就以萬能的 TODO LIST 為例,一起來設計一款 React 的 TodoList 組件吧!

          實現基本功能

          TODO LIST 的功能想必我們應該都比較了解,也就是 TODO 的添加、刪除、修改等等。本身的功能也比較簡單,為了避免示例的復雜度,顯示不同狀態 TODO LIST 的導航(全部、已完成、未完成)的功能我們就不展開了。

          約定目錄結構

          先假設我們已經擁有一個可以運行 React 項目的腳手架(ha~ 因為我不是來教你如何搭建腳手架的),然后項目的源碼目錄 src/ 下可能是這樣的:

          .
          ├── components
          ├── containers
          │   └── App
          │       ├── app.scss
          │       └── index.js
          ├── index.html
          └── index.js

          我們先來簡單解釋下這個目錄設定。我們看到根目錄下的 index.js 文件是整個項目的入口模塊,入口模塊將會處理 DOM 的渲染和 React 組件的熱更新(react-hot-loader)等設置。然后,index.html 是頁面的 HTML 模版文件,這 2 個部分不是我們這次關心的重點,我們不再展開討論。

          入口模塊 index.js 的代碼大概是這樣子的:

          // import reset css, base css...
          
          import React from 'react';
          import ReactDom from 'react-dom';
          import { AppContainer } from 'react-hot-loader';
          import App from 'containers/App';
          
          const render = (Component) => {
            ReactDom.render(
              <AppContainer>
                <Component />
              </AppContainer>,
              document.getElementById('app')
            );
          };
          
          render(App);
          
          if (module.hot) {
            module.hot.accept('containers/App', () => {
              let nextApp = require('containers/App').default;
              
              render(nextApp);
            });
          }

          接下來看 containers/ 目錄,它將放置我們的頁面容器組件,業務邏輯、數據處理等會在這一層做處理,containers/App 將作為我們的頁面主容器組件。作為通用組件,我們將它們放置于 components/ 目錄下。

          基本的目錄結構看起來已經完成,接下來我們實現下主容器組件 containers/App。

          實現主容器

          我們先來看下主容器組件 containers/App/index.js 最初的代碼實現:

          import React, { Component } from 'react';
          import styles from './app.scss';
          
          class App extends Component {
            constructor(props) {
              super(props);
          
              this.state = {
                todos: []
              };
            }
          
            render() {
              return (
                <div className={styles.container}>
                  <h2 className={styles.header}>Todo List Demo</h2>
                  <div className={styles.content}>
                    <header className={styles['todo-list-header']}>
                      <input 
                        type="text"
                        className={styles.input}
                        ref={(input) => this.input = input} 
                      />
                      <button 
                        className={styles.button} 
                        onClick={() => this.handleAdd()}
                      >
                        Add Todo
                      </button>
                    </header>
                    <section className={styles['todo-list-content']}>
                      <ul className={styles['todo-list-items']}>
                        {this.state.todos.map((todo, i) => (
                          <li key={`${todo.text}-${i}`}>
                            <em 
                              className={todo.completed ? styles.completed : ''} 
                              onClick={() => this.handleStateChange(i)}
                            >
                              {todo.text}
                            </em>
                            <button 
                              className={styles.button} 
                              onClick={() => this.handleRemove(i)}
                            >
                              Remove
                            </button>
                          </li>
                        ))}
                      </ul>
                    </section>
                  </div>
                </div>
              );
            }
          
            handleAdd() {
              ...
            }
          
            handleRemove(index) {
              ...
            }
          
            handleStateChange(index) {
              ...
            }
          }
          
          export default App;

          我們可以像上面這樣把所有的業務邏輯一股腦的塞進主容器中,但我們要考慮到主容器隨時會組裝其他的組件進來,將各種邏輯堆放在一起,到時候這個組件就會變得無比龐大,直到“無法收拾”。所以,我們得分離出一個獨立的 TodoList 組件。

          分離組件

          TodoList 組件

          在 components/ 目錄下,我們新建一個 TodoList 文件夾以及相關文件:

          .
          ├── components
          +│   └── TodoList
          +│       ├── index.js
          +│       └── todo-list.scss
          ├── containers
          │   └── App
          │       ├── app.scss
          │       └── index.js
          ...

          然后我們將 containers/App/index.js 下跟 TodoList 組件相關的功能抽離到 components/TodoList/index.js 中:

          ...
          import styles from './todo-list.scss';
          
          export default class TodoList extends Component {
            ...
            
            render() {
              return (
                <div className={styles.container}>
          -       <header className={styles['todo-list-header']}>
          +       <header className={styles.header}>
                    <input 
                      type="text"
                      className={styles.input}
                      ref={(input) => this.input = input} 
                    />
                    <button 
                      className={styles.button} 
                      onClick={() => this.handleAdd()}
                    >
                      Add Todo
                    </button>
                  </header>
          -       <section className={styles['todo-list-content']}>
          +       <section className={styles.content}>
          -         <ul className={styles['todo-list-items']}>
          +         <ul className={styles.items}>
                      {this.state.todos.map((todo, i) => (
                        <li key={`${todo}-${i}`}>
                          <em 
                            className={todo.completed ? styles.completed : ''} 
                            onClick={() => this.handleStateChange(i)}
                          >
                            {todo.text}
                          </em>
                          <button 
                            className={styles.button} 
                            onClick={() => this.handleRemove(i)}
                          >
                            Remove
                          </button>
                        </li>
                      ))}
                    </ul>
                  </section>
                </div>
              );
            }
          
            ...
          }

          有沒有注意到上面 render 方法中的 className,我們省去了 todo-list* 前綴,由于我們用的是 CSS MODULES,所以當我們分離組件后,原先在主容器中定義的 todo-list* 前綴的 className ,可以很容易通過 webpack 的配置來實現:

          ...
          module.exports = {
            ...
            module: {
              rules: [
                {
                  test: /\.s?css/,
                  use: [
                    'style-loader',
                    {
                      loader: 'css-loader',
                      options: {
                        modules: true,
                        localIdentName: '[name]--[local]-[hash:base64:5]'
                      }
                    },
                    ...
                  ]
                }
              ]  
            }
            ...
          };

          我們再來看下該組件的代碼輸出后的結果:

          <div data-reactroot="" class="app--container-YwMsF">
            ...
              <div class="todo-list--container-2PARV">
                <header class="todo-list--header-3KDD3">
                  ...
                </header>
                <section class="todo-list--content-3xwvR">
                  <ul class="todo-list--items-1SBi6">
                    ...
                  </ul>
                </section>
              </div>
          </div>

          從上面 webpack 的配置和輸出的 HTML 中可以看到,className 的命名空間問題可以通過語義化 *.scss 文件名的方式來實現,比如 TodoList 的樣式文件 todo-list.scss。這樣一來,省去了我們定義組件 className 的命名空間帶來的煩惱,從而只需要從組件內部的結構下手。

          回到正題,我們再來看下分離 TodoList 組件后的 containers/App/index.js:

          import TodoList from 'components/TodoList';
          ...
          
          class App extends Component {
            render() {
              return (
                <div className={styles.container}>
                  <h2 className={styles.header}>Todo List Demo</h2>
                  <div className={styles.content}>
                    <TodoList />
                  </div>
                </div>
              );
            }
          }
          
          export default App;

          抽離通用組件

          作為一個項目,當前的 TodoList 組件包含了太多的子元素,如:input、button 等。為了讓組件“一次編寫,隨處使用”的原則,我們可以進一步拆分 TodoList 組件以滿足其他組件的使用。

          但是,如何拆分組件才是最合理的呢?我覺得這個問題沒有最好的答案,但我們可以從幾個方面進行思考:可封裝性、可重用性和靈活性。比如拿 h1 元素來講,你可以封裝成一個 Title 組件,然后這樣 <Title text={title} /> 使用,又或者可以這樣 <Title>{title}</Title> 來使用。但你有沒有發現,這樣實現的 Title 組件并沒有起到簡化和封裝的作用,反而增加了使用的復雜度,對于 HTML 來講,h1 本身也是一個組件,所以我們拆分組件也是需要掌握一個度的。

          好,我們先拿 input 和 button 下手,在 components/ 目錄下新建 2 個 Button 和 Input 組件:

          .
          ├── components
          +│   ├── Button
          +│   │   ├── button.scss
          +│   │   └── index.js
          +│   ├── Input
          +│   │   ├── index.js
          +│   │   └── input.scss
          │   └── TodoList
          │       ├── index.js
          │       └── todo-list.scss
          ...

          Button/index.js 的代碼:

          ...
          export default class Button extends Component {
            render() {
              const { className, children, onClick } = this.props;
          
              return (
                <button 
                  type="button" 
                  className={cn(styles.normal, className)} 
                  onClick={onClick}
                >
                  {children}
                </button>
              );
            }
          }

          Input/index.js 的代碼:

          ...
          export default class Input extends Component {
            render() {
              const { className, value, inputRef } = this.props;
          
              return (
                <input 
                  type="text"
                  className={cn(styles.normal, className)}
                  defaultValue={value}
                  ref={inputRef} 
                />
              );
            }
          }

          由于這 2 個組件自身不涉及任何業務邏輯,應該屬于純渲染組件(木偶組件),我們可以使用 React 輕量的無狀態組件的方式來聲明:

          ...
          const Button = ({ className, children, onClick }) => (
            <button 
              type="button" 
              className={cn(styles.normal, className)} 
              onClick={onClick}
            >
              {children}
            </button>
          );

          是不是覺得酷炫很多!

          另外,從 Input 組件的示例代碼中看到,我們使用了非受控組件,這里是為了降低示例代碼的復雜度而特意為之,大家可以根據自己的實際情況來決定是否需要設計成受控組件。一般情況下,如果不需要獲取實時輸入值的話,我覺得使用非受控組件應該夠用了。

          我們再回到上面的 TodoList 組件,將之前分離的子組件 Button,Input 組裝進來。

          ...
          import Button from 'components/Button';
          import Input from 'components/Input';
          ...
          
          export default class TodoList extends Component {
            render() {
              return (
                <div className={styles.container}>
                  <header className={styles.header}>
                    <Input 
                      className={styles.input} 
                      inputRef={(input) => this.input = input} 
                    />
                    <Button onClick={() => this.handleAdd()}>
                      Add Todo
                    </Button>
                  </header>
                  ...
                </div>
              );
            }
          }
          
          ...

          拆分子組件

          然后繼續接著看 TodoList 的 items 部分,我們注意到這部分包含了較多的渲染邏輯在 render 中,導致我們需要浪費對這段代碼與上下文之間會有過多的思考,所以,我們何不把它抽離出去:

          ...
          
          export default class TodoList extends Component {
            render() {
              return (
                <div className={styles.container}>
                  ...
                  <section className={styles.content}>
                    {this.renderItems()}
                  </section>
                </div>
              );
            }
          
            renderItems() {
              return (
                <ul className={styles.items}>
                  {this.state.todos.map((todo, i) => (
                    <li key={`${todo}-${i}`}>
                      ...
                    </li>
                  ))}
                </ul>
              );
            }
            
            ...
          }

          上面的代碼看似降低了 render 的復雜度,但仍然沒有讓 TodoList 減少負擔。既然我們要把這部分邏輯分離出去,我們何不創建一個 Todos 組件,把這部分邏輯拆分出去呢?so,我們以“就近聲明”的原則在 components/TodoList/ 目錄下創建一個子目錄components/TodoList/components/ 來存放 TodoList 的子組件 。why?因為我覺得 組件 Todos 跟 TodoList 有緊密的父子關系,且跟其他組件間也不太會有任何交互,也可以認為它是 TodoList 私有的。

          然后我們預覽下現在的目錄結構:

          .
          ├── components
          │   ...
          │   └── TodoList
          +│       ├── components
          +│       │   └── Todos
          +│       │       ├── index.js
          +│       │       └── todos.scss
          │       ├── index.js
          │       └── todo-list.scss

          Todos/index.js 的代碼:

          ...
          const Todos = ({ data: todos, onStateChange, onRemove }) => (
            <ul className={styles.items}>
              {todos.map((todo, i) => (
                <li key={`${todo}-${i}`}>
                  <em 
                    className={todo.completed ? styles.completed : ''} 
                    onClick={() => onStateChange(i)}
                  >
                    {todo.text}
                  </em>
                  <Button onClick={() => onRemove(i)}>
                    Remove
                  </Button>
                </li>
              ))}
            </ul>
          );
          ...

          再看拆分后的 TodoList/index.js :

          render() {
            return (
              <div className={styles.container}>
                ...
                <section className={styles.content}>
                  <Todos 
                    data={this.state.todos}
                    onStateChange={(index) => this.handleStateChange(index)}
                    onRemove={(index) => this.handleRemove(index)}
                  />
                </section>
              </div>
            );
          }

          增強子組件

          到目前為止,大體上的功能已經搞定,子組件看上去拆分的也算合理,這樣就可以很容易的增強某個子組件的功能了。就拿 Todos 來說,在新增了一個 TODO 后,假如我們并沒有完成這個 TODO,而我們又希望可以修改它的內容了。ha~不要著急,要不我們再拆分下這個 Todos,比如增加一個 Todo 組件:

          .
          ├── components
          │   ...
          │   └── TodoList
          │       ├── components
          +│       │   ├── Todo
          +│       │   │   ├── index.js
          +│       │   │   └── todo.scss
          │       │   └── Todos
          │       │       ├── index.js
          │       │       └── todos.scss
          │       ├── index.js
          │       └── todo-list.scss

          先看下 Todos 組件在抽離了 Todo 后的樣子:

          ...
          import Todo from '../Todo';
          ...
          
          const Todos = ({ data: todos, onStateChange, onRemove }) => (
            <ul className={styles.items}>
              {todos.map((todo, i) => (
                <li key={`${todo}-${i}`}>
                  <Todo
                    {...todo}
                    onClick={() => onStateChange(i)}
                  />
                  <Button onClick={() => onRemove(i)}>
                    Remove
                  </Button>
                </li>
              ))}
            </ul>
          );
          
          export default Todos;
          

          我們先不關心 Todo 內是何如實現的,就如我們上面說到的那樣,我們需要對這個 Todo 增加一個可編輯的功能,從單純的屬性配置入手,我們只需要給它增加一個 editable 的屬性:

          <Todo
            {...todo}
          + editable={editable}
            onClick={() => onStateChange(i)}
          />

          然后,我們再思考下,在 Todo 組件的內部,我們需要重新組織一些功能邏輯:

          • 根據傳入的 editable 屬性來判斷是否需要顯示編輯按鈕

          • 根據組件內部的編輯狀態,是顯示文本輸入框還是文本內容

          • 點擊“更新”按鈕后,需要通知父組件更新數據列表

          我們先來實現下 Todo 的第一個功能點:

          render() {
            const { completed, text, editable, onClick } = this.props;
          
            return (
              <span className={styles.wrapper}>
                <em
                  className={completed ? styles.completed : ''} 
                  onClick={onClick}
                  >
                  {text}
                </em>
                {editable && 
                  <Button>
                    Edit
                  </Button>
                }
              </span>
            );
          }

          顯然實現這一步似乎沒什么 luan 用,我們還需要點擊 Edit 按鈕后能顯示 Input 組件,使內容可修改。所以,簡單的傳遞屬性似乎無法滿足該組件的功能,我們還需要一個內部狀態來管理組件是否處于編輯中:

          render() {
            const { completed, text, editable, onStateChange } = this.props,
              { editing } = this.state;
          
            return (
              <span className={styles.wrapper}>
                {editing ? 
                  <Input 
                    value={text}
                    className={styles.input}
                    inputRef={input => this.input = input}
                  /> :
                  <em
                    className={completed ? styles.completed : ''} 
                    onClick={onStateChange}
                  >
                    {text}
                  </em>
                }
                {editable && 
                  <Button onClick={() => this.handleEdit()}>
                    {editing ? 'Update' : 'Edit'}
                  </Button>
                }
              </span>
            );
          }

          最后,Todo 組件在點擊 Update 按鈕后需要通知父組件更新數據:

          handleEdit() {
            const { text, onUpdate } = this.props;
            let { editing } = this.state;
          
            editing = !editing;
          
            this.setState({ editing });
          
            if (!editing && this.input.value !== text) {
              onUpdate(this.input.value);
            }
          }

          需要注意的是,我們傳遞的是更新后的內容,在數據沒有任何變化的情況下通知父組件是毫無意義的。

          我們再回過頭來修改下 Todos 組件對 Todo 的調用。先增加一個由 TodoList 組件傳遞下來的回調屬性 onUpdate,同時修改onClick 為 onStateChange,因為這時的 Todo 已不僅僅只有單個點擊事件了,需要定義不同狀態變更時的事件回調:

          <Todo
            {...todo}
            editable={editable}
          - onClick={() => onStateChange(i)}
          + onStateChange={() => onStateChange(i)}
          + onUpdate={(value) => onUpdate(i, value)}
          />

          而最終我們又在 TodoList 組件中,增加 Todo 在數據更新后的業務邏輯。

          TodoList 組件的 render 方法內的部分示例代碼:

          <Todos 
            editable
            data={this.state.todos}
          + onUpdate={(index, value) => this.handleUpdate(index, value)}
            onStateChange={(index) => this.handleStateChange(index)}
            onRemove={(index) => this.handleRemove(index)}
          />

          TodoList 組件的 handleUpdate 方法的示例代碼:

          handleUpdate(index, value) {
            let todos = [...this.state.todos];
            const target = todos[index];
          
            todos = [
              ...todos.slice(0, index),
              {
                text: value,
                completed: target.completed
              },
              ...todos.slice(index + 1)
            ];
          
            this.setState({ todos });
          }

          組件數據管理

          既然 TodoList 是一個組件,初始狀態 this.state.todos 就有可能從外部傳入。對于組件內部,我們不應該過多的關心這些數據從何而來(可能通過父容器直接 Ajax 調用后返回的數據,或者 Redux、MobX 等狀態管理器獲取的數據),我覺得組件的數據屬性的設計可以從以下 3 個方面來考慮:

          • 在沒有初始數據傳入時應該提供一個默認值

          • 一旦數據在組件內部被更新后應該及時的通知父組件

          • 當有新的數據(從后端 API 請求的)傳入組件后,應該重新更新組件內部狀態

          根據這幾點,我們可以對 TodoList 再做一番改造。

          首先,對 TodoList 增加一個 todos 的默認數據屬性,使父組件在沒有傳入有效屬性值時也不會影響該組件的使用:

          export default class TodoList extends Component {
            constructor(props) {
              super(props);
          
              this.state = {
                todos: props.todos
              };
            }
            ...
          }
          
          TodoList.defaultProps = {
            todos: []
          };

          然后,再新增一個內部方法 this.update 和一個組件的更新事件回調屬性 onUpdate,當數據狀態更新時可以及時的通知父組件:

          export default class TodoList extends Component {
            ...
            handleAdd() {
              ...
              this.update(todos);
            }
          
            handleUpdate(index, value) {
              ...
              this.update(todos);
            }
          
            handleRemove(index) {
              ...
              this.update(todos);
            }
          
            handleStateChange(index) {
              ...
              this.update(todos);
            }
          
            update(todos) {
              const { onUpdate } = this.props;
          
              this.setState({ todos });
              onUpdate && onUpdate(todos);
            }
          }

          這就完事兒了?No! No! No! 因為 this.state.todos 的初始狀態是由外部 this.props 傳入的,假如父組件重新更新了數據,會導致子組件的數據和父組件不同步。那么,如何解決?

          我們回顧下 React 的生命周期,父組件傳遞到子組件的 props 的更新數據可以在 componentWillReceiveProps 中獲取。所以我們有必要在這里重新更新下 TodoList 的數據,哦!千萬別忘了判斷傳入的 todos 和當前的數據是否一致,因為,當任何傳入的 props 更新時都會導致 componentWillReceiveProps 的觸發。

          componentWillReceiveProps(nextProps) {
            const nextTodos = nextProps.todos;
          
            if (Array.isArray(nextTodos) && !_.isEqual(this.state.todos, nextTodos)) {
              this.setState({ todos: nextTodos });
            }
          }

          注意代碼中的 _.isEqual,該方法是 Lodash 中非常實用的一個函數,我經常拿來在這種場景下使用。

          結尾

          由于本人對 React 的了解有限,以上示例中的方案可能不一定最合適,但你也看到了 TodoList 組件,既可以是包含多個不同功能邏輯的大組件,也可以拆分為獨立、靈巧的小組件,我覺得我們只需要掌握一個度。當然,如何設計取決于你自己的項目,正所謂:沒有最好的,只有更合適的。還是希望本篇文章能給你帶來些許的小收獲。


          站長推薦

          1.阿里云: 本站目前使用的是阿里云主機,安全/可靠/穩定。點擊領取2000元代金券、了解最新阿里云產品的各種優惠活動點擊進入

          2.騰訊云: 提供云服務器、云數據庫、云存儲、視頻與CDN、域名等服務。騰訊云各類產品的最新活動,優惠券領取點擊進入

          3.廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入

          鏈接: http://www.modern-decoration.com.cn/article/detial/93

          從 React 切換到 Vue.js

          React 和 Vue 的關系有點像可口可樂和百事可樂,你在 React 中做的很多事情都可以在 Vue 中完成。當然這里也存在一些重要的概念差異,其中一些反映了 Angular 對 Vue 的影響。

          React常用hook的優化useEffect淺比較

          先說說react原版的useEffect使用起來不便的地方,這里的effect每次更新都會執行,因為第三個參數一直是不等的,第二是在deps依賴很多的時候是真的麻煩

          react依賴node嗎?

          學習React前提必須擁有Javascript和DOM知識。這個門檻已經很低了。但是很多的教程里面都提到npm,nodejs.要先安裝nodejs。但是react并不依賴node。

          React setState 這樣用,開發直呼內行!

          眾所周知, React 是通過管理狀態來實現對組件的管理,而setState是用于改變狀態的最基本的一個方法,雖然基礎,但是其實并不容易掌握,本文將結合部分源碼對這個方法做一個相對深入的解析。

          使用react-app-rewired和customize-cra對默認webpack自定義配置

          最近在學習react框架,之前一直都是用vue 開發,知道在vue 中知道如何配置一下相關的webpack 有助于開發,學react 過程中,我也在想這些該怎么配置啊,所以就有這篇文章

          新手學習 react 迷惑的點

          網上各種言論說 React 上手比 Vue 難,可能難就難不能深刻理解 JSX,或者對 ES6 的一些特性理解得不夠深刻,導致覺得有些點難以理解,然后說 React 比較難上手,還反人類啥的

          10分鐘快速了解 React 基礎

          如果你還不會 React,希望本文可以幫你快速了解 React.js 的基礎知識。使用 create-react-app 工具快速創建 React SPA。render 函數中提到了 JSX,簡單的看,就是一個可以在 js 中寫 html

          如何使用React搭建前端?

          首先說明node.js、npm、cnpm分別是做什么的?node.js簡單的說 Node.js 就是運行在服務端的 JavaScript,安裝了node.js默認安裝了npm,可以使用npm -v查看是否安裝。

          React中編寫CSS的姿勢

          在任何環境之下其實沒有最佳,最有最適合,那么在React中編寫CSS也是類似的。在React中有很多編寫CSS的方式,在社區中討論最多的應該是CSS In JS 和 CSS Modules

          react如何通過shouldComponentUpdate來減少重復渲染

          在react開發中,經常會遇到組件重復渲染的問題,父組件一個state的變化,就會導致以該組件的所有子組件都重寫render,盡管絕大多數子組件的props沒有變化

          內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權或違規,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全運營推廣

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网