Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

写给Vue开发者入门React的教程 #176

Open
ly2011 opened this issue Jul 10, 2019 · 0 comments
Open

写给Vue开发者入门React的教程 #176

ly2011 opened this issue Jul 10, 2019 · 0 comments
Labels

Comments

@ly2011
Copy link
Owner

ly2011 commented Jul 10, 2019

For the past three years, I’ve been using both React and Vue in different projects, ranging from smaller websites to large scale apps.

在过去的三年里,我一直在不同的项目中使用 React 和 Vue,范围从小型网站到大型应用程序。

Last month I wrote a post about why I prefer React over Vue. Shortly after I joined Adam Wathan on Full Stack Radio to talk about React from a Vue developer’s perspective.

上个月,我写了一篇关于为什么我更喜欢 React 而不是 Vue 的帖子。 在我加入 Adam Wathan 的全栈收音机之后不久,我从一个 Vue 开发者的角度讨论了 React。

We covered a lot of ground on the podcast, but most things we talked about could benefit from some code snippets to illustrate their similaraties and differences.

我们在播客中涉及了很多内容,但是我们讨论的大多数内容都可以从一些代码片段中获益,以说明它们的相似之处和不同之处。

This post is a succinct rundown of most Vue features, and how I would write them with React in 2019 with hooks.

这篇文章简明扼要地概述了 Vue 的大多数特性,以及我将如何在2019年用钩子写它们。

Did I miss anything? Are there other comparisons you’d like to see? Or do you just want to share your thoughts about Vue or React? Talk to me on Twitter!

我错过什么了吗? 你还想看到其他的比较吗? 或者你只是想分享你关于 Vue 的想法或者做出反应? 在推特上和我聊天吧!

Table of contents

目录

Templates

模板

React alternative: JSX

反应备选: JSX

Vue uses HTML strings with some custom directives for templating. They recommend using .vue files to seperate the templates and script (and optionally styles).

Vue 使用 HTML 字符串和一些用于模板的自定义指令。 他们建议使用。 Vue 文件分离模板和脚本(和可选样式)。

<!-- Greeter.vue -->

<template>
  <p>Hello, {{ name }}!</p>
</template>

<script>
export default {
  props: ['name']
};
</script>

React uses JSX, which is an extension of ECMAScript.

使用 JSX,它是 ECMAScript 的一个扩展。

export default function Greeter({ name }) {
  return <p>Hello, {name}!</p>;
}

Conditional rendering

条件呈现

React alternative: Logical && operator, ternary statements, or early returns

反应替代: 逻辑 & & 操作符,三元语句,或早期返回

Vue uses v-if, v-else and v-else-if directives to conditionally render parts of a template.

Vue 使用 v-if、 v-else 和 v-else-if 指令有条件地呈现模板的部分。

<!-- Awesome.vue -->

<template>
  <article>
    <h1 v-if="awesome">Vue is awesome!</h1>
  </article>
</template>

<script>
export default {
  props: ['awesome']
};
</script>

React doesn’t support directives, so you need to use the language to conditionally return parts of a template.

React 不支持指令,因此需要使用该语言有条件地返回模板的部分内容。

The && operator provides a succinct way to write an if statement.

& 运算符提供了一种简洁的方式来编写 if 语句。

export default function Awesome({ awesome }) {
  return (
    <article>
      {awesome && <h1>React is awesome!</h1>};
    </article>
  );
}

If you need an else clause, use a ternary statement instead.

如果需要 else 子句,可以使用三元语句。

export default function Awesome({ awesome }) {
  return (
    <article>
      {awesome ? (
        <h1>React is awesome!</h1>
      ) : (
        <h1>Oh no 😢</h1>
      )};
    </article>
}

You could also opt to keep the two branches completely separated, and use an early return instead.

您还可以选择将两个分支完全分离,并使用提前返回代替。

export default function Awesome({ awesome }) {
  if (!awesome) {
    return (
      <article>
        <h1>Oh no 😢</h1>
      </article>
    );
  }

  return (
    <article>
      <h1>React is awesome!</h1>
    </article>
  );
}

List rendering

列表呈现

React alternative: Array.map

反应方式: ary.map

Vue uses the v-for directive to loop over arrays and objects.

Vue 使用 v-for 指令对数组和对象进行循环。

<!-- Recipe.vue -->

<template>
  <ul>
    <li v-for="(ingredient, index) in ingredients" :key="index">
      {{ ingredient }}
    </li>
  </ul>
</template>

<script>
export default {
  props: ['ingredients']
};
</script>

With React, you can “map” the array to a set of elements using the built in Array.map function.

使用 React,您可以使用内置的 Array.map 函数将数组"映射"到一组元素。

export default function Recipe({ ingredients }) {
  return (
    <ul>
      {ingredients.map((ingredient, index) => (
        <li key={index}>{ingredient}</li>
      ))}
    </ul>
  );
}

Iterating objects is a bit trickier. Vue allows you to use the same v-fordirective for keys & values.

迭代对象有点棘手。 Vue 允许您对键和值使用相同的 v- 指令。

<!-- KeyValueList.vue -->

<template>
  <ul>
    <li v-for="(value, key) in object" :key="key">
      {{ key }}: {{ value }}
    </li>
  </ul>
</template>

<script>
export default {
  props: ['object'] // E.g. { a: 'Foo', b: 'Bar' }
};
</script>

I like to use the built in Object.entries function with React to iterate over objects.

我喜欢在 React 中使用内置的 Object.entries 函数来迭代对象。

export default function KeyValueList({ object }) {
  return (
    <ul>
      {Object.entries(object).map(([key, value]) => (
        <li key={key}>{value}</li>
      ))}
    </ul>
  );
}

Class and style bindings

类和样式绑定

React alternative: Manually pass props

反应方式: 手动传球

Vue automatically binds class and style props to the outer HTML element of a component.

Vue 自动将类和样式道具绑定到组件的外部 HTML 元素。

<!-- Post.vue -->

<template>
  <article>
    <h1>{{ title }}</h1>
  </article>
</template>

<script>
export default {
  props: ['title'],
};
</script>

<!--
<post
  :title="About CSS"
  class="margin-bottom"
  style="color: red"
/>
-->

With React, you need to manually pass className and style props. Note that style must be an object with React, strings are not supported.

使用 React,您需要手动传递 className 和 style props。 注意,样式必须是具有 React 的对象,不支持字符串。

export default function Post({ title, className, style }) {
  return (
    <article className={className} style={style}>
      {title}
    </article>
  );
}

{/* <Post
  title="About CSS"
  className="margin-bottom"
  style={{ color: 'red' }}
/> */}

If you want to pass down all remaining props, the object rest spread operator comes in handy.

如果你想传递所有剩余的道具,对象休息传播运算符派上用场。

export default function Post({ title, ...props }) {
  return (
    <article {...props}>
      {title}
    </article>
  );
}

If you miss Vue’s excellent class API, look into Jed Watson’s classnameslibrary.

如果您错过了 Vue 优秀的类 API,请查看 Jed Watson 的类名库。

Props

道具

React alternative: Props

反应替代品: 道具

Props behave pretty much the same way in React as Vue. One minor difference: React components won’t inherit unknown attributes.

道具在 React as Vue 中的表现几乎相同。 一个小小的区别: 反应组件不会继承未知的属性。

<!-- Post.vue -->

<template>
  <h1>{{ title }}</h1>
</template>

<script>
export default {
  props: ['title'],
};
</script>
export default function Post({ title }) {
  return <h3>{title}</h3>;
}

Using expressions as props in Vue is possible with a : prefix, which is an alias for the v-bind directive. React uses curly braces for dynamic values.

在 Vue 中使用表达式作为 props 可以使用: 前缀,这是 v-bind 指令的别名。 React 为动态值使用花括号。

<!-- Post.vue -->

<template>
  <post-title :title="title" />
</template>

<script>
export default {
  props: ['title'],
};
</script>
export default function Post({ title }) {
  return <PostTitle title={title} />;
}

Data

数据

React alternative: The useState hook

反应方案: 美国房地产挂钩

In Vue the data option is used to store local component state.

在 Vue 中,数据选项用于存储本地组件状态。

<!-- ButtonCounter.vue -->

<template>
  <button @click="count++">
    You clicked me {{ count }} times.
  </button>
</template>

<script>
export default {
  data() {
    return {
      count: 0
    }
  }
};
</script>

React exposes a useState hook which returns a two-element array containing the current state value and a setter function.

React 公开一个 useState 挂钩,该挂钩返回一个包含当前状态值和 setter 函数的两元素数组。

import { useState } from 'react';

export default function ButtonCounter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}

You can choose whether you prefer to distribute state between multiple useState calls, or keep it in a single object.

您可以选择是在多个 useState 调用之间分发状态,还是将其保存在单个对象中。

import { useState } from 'react';

export default function ProfileForm() {
  const [name, setName] = useState('Sebastian');
  const [email, setEmail] = useState('sebastian@spatie.be');

  // ...
}
import { useState } from 'react';

export default function ProfileForm() {
  const [values, setValues] = useState({
    name: 'Sebastian',
    email: 'sebastian@spatie.be'
  });

  // ...
}

v-model

V 型

v-model is a convenient Vue directive that combines passing down a value prop with listening to an input event. This makes it look like Vue does two-way binding, while it’s still just “props down, events up” under the hood.

V-model 是一个方便的 Vue 指令,它结合了传递值支撑和倾听输入事件。 这使它看起来像 Vue 做双向绑定,而它仍然只是"道具下来,事件上来"的引擎盖下。

<!-- Profile.vue -->

<template>
  <input type="text" v-model="name" />
</template>

<script>
export default {
  data() {
    return {
      name: 'Sebastian'
    }
  }
};
</script>

Vue expands the v-model directive to the following:

Vue 将 v-model 指令扩展为以下内容:

<template>
  <input
    type="text"
    :value="name"
    @input="name = $event.target.value"
  />
</template>

React doesn’t have a v-model equivalent. You always need to be explicit:

反应并没有 v-model 的等价物。 你总是需要明确:

import { useState } from 'react';

export default function Profile() {
  const [name, setName] = useState('Sebastian');

  return (
    <input
      type="text"
      value={name}
      onChange={event => setName(event.target.name)}
    />
  );
}

Computed properties

计算属性

React alternative: Variables, optionally wrapped in useMemo

反应替代: 变量,可以选择包装在 usemo 中

Vue has computed properties for two reasons: to avoid mixing logic and markup in templates, and to cache complex computations in a component instance.

Vue 使用计算属性有两个原因: 避免在模板中混合使用逻辑和标记,以及在组件实例中缓存复杂的计算。

Without computed properties:

没有计算属性:

<!-- ReversedMessage.vue -->

<template>
  <p>{{ message.split('').reverse().join('') }}</p>
</template>

<script>
export default {
  props: ['message']
};
</script>
export default function ReversedMessage({ message }) {
  return <p>{message.split('').reverse().join('')}</p>;
}

With React, you can extract the computation from the template by assigning the result to a variable.

使用 React,您可以通过将结果分配给一个变量来从模板中提取计算。

<!-- ReversedMessage.vue -->

<template>
  <p>{{ reversedMessage }}</p>
</template>

<script>
export default {
  props: ['message'],

  computed: {
    reversedMessage() {
      return this.message.split('').reverse().join('');
    }
  }
};
</script>
export default function ReversedMessage({ message }) {
  const reversedMessage = message.split('').reverse().join('');

  return <p>{reversedMessage}</p>;
}

If performance is a concern, the computation can be wrapped in a useMemo hook. useMemo requires a callback that returns a computed result, and an array of dependencies.

如果性能是一个问题,那么计算可以包装在 usemo 钩子中。 Usemo 需要返回计算结果的回调和依赖项数组。

In the following example, reversedMessage will only be recomputed if the message dependency changes.

在下面的示例中,只有在消息依赖关系发生更改时,才会重新计算 reversedMessage。

import { useMemo } from 'react';

export default function ReversedMessage({ message }) {
  const reversedMessage = useMemo(() => {
    return message.split('').reverse().join('');
  }, [message]);

  return <p>{reversedMessage}</p>;
}

Methods

方法

React alternative: Functions

反应替代: 功能

Vue has a methods option to declare functions that can be used throughout the component.

Vue 有一个方法选项来声明可以在整个组件中使用的函数。

<!-- ImportantButton.vue -->

<template>
  <button onClick="doSomething">
    Do something!
  </button>
</template>

<script>
export default {
  methods: {
    doSomething() {
      // ...
    }
  }
};
</script>

In React you can declare plain functions inside our component.

在响应中,您可以在组件中声明普通函数。

export default function ImportantButton() {
  function doSomething() {
    // ...
  }

  return (
    <button onClick={doSomething}>
      Do something!
    </button>
  );
}

Events

活动

React alternative: Callback props

反应: 回调道具

Events are essentially callbacks that are called when something happened in the child component. Vue sees events as a first-class citizen, so you can “listen” to them with @, which is shorthand for the v-ondirective.

事件本质上是在子组件中发生事件时调用的回调。 Vue 将事件视为一个第一类物件,因此您可以使用@"listen"来"listen"它们,@是 v-on 指令的简写。

<!-- PostForm.vue -->

<template>
  <form>
    <button type="button" @click="$emit('save')">
      Save
    </button>
    <button type="button" @click="$emit('publish')">
      Publish
    </button>
  </form>
</template>

Events don’t have any special meaning in React, they’re just callback props will be called by the child component.

事件在 React 中没有任何特殊含义,它们只是由 child 组件调用的回调道具。

export default function PostForm({ onSave, onPublish }) {
  return (
    <form>
      <button type="button" onClick={onSave}>
        Save
      </button>
      <button type="button" onClick={onPublish}>
        Publish
      </button>
    </form>
  );
}

Event modifiers

事件修饰符

React alternative: Higher order functions if you really want

反应替代: 高阶函数,如果你真的想要

Vue has a few modifiers like prevent and stop to change the way an event is handled without touching it’s handler.

Vue 有一些修饰符,比如 prevent 和 stop,可以在不接触事件处理程序的情况下更改事件的处理方式。

<!-- AjaxForm.vue -->

<template>
  <form @submit.prevent="submitWithAjax">
    <!-- ... -->
  </form>
</template>

<script>
export default {
  methods: {
    submitWithAjax() {
      // ...
    }
  }
};
</script>

There’s no modifier syntax in React. Preventing defaults and stopping propagation is mostly handled in the callback.

在 React 中没有修饰语语法。 预防缺省值和停止传播主要是在回调中处理的。

export default function AjaxForm() {
  function submitWithAjax(event) {
    event.preventDefault();
    // ...
  }

  return (
    <form onSubmit={submitWithAjax}>
      {/* ... */}
    </form>
  );
}

If you really want to have something modifier-like, you could use a higher order function.

如果你真的想要一些类似修饰符的东西,你可以使用一个高阶函数。

function prevent(callback) {
  return (event) => {
      event.preventDefault();
      callback(event);
  };
}

export default function AjaxForm() {
  function submitWithAjax(event) {
    // ...
  }

  return (
    <form onSubmit={prevent(submitWithAjax)}>
      {/* ... */}
    </form>
  );
}

Lifecycle methods

生命周期方法

React alternative: The useEffect hook

反应方式: 使用效果钩子

DISCLAIMER

免责声明

With class components, React has a very similar API to Vue when it comes to the component lifecycle. With hooks, most lifecycle-related problems can be solved with useEffect. Effects and lifecycle methods are completely different paradigms, so they're hard to compare. In turn, this section is limited to a few practical examples, as effects deserve their own article.

对于类组件,当涉及到组件生命周期时,React 有一个与 Vue 非常类似的 API。 使用钩子,大多数与生命周期相关的问题可以使用 useEffect 来解决。 效果和生命周期方法是完全不同的范例,所以它们很难比较。 反过来,这一节仅限于几个实际例子,因为效果值得自己的文章。

A common case for lifecycle methods is to set up and tear down third party libraries.

生命周期方法的一个常见案例是建立和拆除第三方库。

<template>
  <input type="text" ref="input" />
</template>

<script>
import DateTimePicker from 'awesome-date-time-picker';

export default {
  mounted() {
   this.dateTimePickerInstance =
     new DateTimePicker(this.$refs.input);
  },

  beforeDestroy() {
    this.dateTimePickerInstance.destroy();
  }
};
</script>

With useEffect, you can declare a “side effect” that needs to run after a render. When you return a callback from useEffect, it will be invoked when the effect gets cleaned up. In this case, when the component is destroyed.

使用 useEffect,你可以声明一个需要在渲染后运行的"副作用"。 当你从 useEffect 返回一个回调函数时,它会在效果被清除时被调用。 在本例中,当组件被销毁时。

import { useEffect, useRef } from 'react';
import DateTimePicker from 'awesome-date-time-picker';

export default function Component() {
  const dateTimePickerRef = useRef();

  useEffect(() => {
    const dateTimePickerInstance =
      new DateTimePicker(dateTimePickerRef.current);

    return () => {
      dateTimePickerInstance.destroy();
    };
  }, []);

  return <input type="text" ref={dateTimePickerRef} />;
}

This looks similar to registering a beforeDestroy listener in mounted in a Vue component.

这看起来类似于在 Vue 组件中的挂载中注册 beforeDestroy 侦听器。

<script>
export default {
  mounted() {
    const dateTimePicker =
      new DateTimePicker(this.$refs.input);

    this.$once('hook:beforeDestroy', () => {
      dateTimePicker.destroy();
    });
  }
};
</script>

Similar to useMemo, useEffect accepts an array of dependencies as a second parameter.

与 usemo 类似,useEffect 接受依赖项数组作为第二个参数。

Without any specified dependencies, the effect will run after every render, and will clean up before every next render. This functionality is similar to a combination of mounted, updated, beforeUpdate and beforeDestroy.

如果没有任何指定的依赖项,效果将在每次渲染之后运行,并在每次下一次渲染之前清除。 此功能类似于挂载、更新、 beforeUpdate 和 beforeDestroy 的组合。

useEffect(() => {
    // Happens after every render

    return () => {
        // Optional; clean up before next render
    };
});

If you specify that the effect has no dependencies, the effect will only run when the component renders the first time, because it has no reason to update. This functionality is similar to a combination of mounted, and beforeDestroyed.

如果指定该效果没有依赖项,则该效果只会在组件第一次呈现时运行,因为它没有理由进行更新。 这个功能类似于挂载和 beforeDestroyed 的组合。

useEffect(() => {
    // Happens on mount

    return () => {
        // Optional; clean up before unmount
    };
}, []);

If you specify a dependency, the effect will only run when the dependency changes. We’ll get back to this in the watchers section.

如果指定依赖项,则只有在依赖项更改时才会运行效果。 我们将在观察者部分回到这个问题。

const [count, setCount] = useState(0);

useEffect(() => {
    // Happens when `count` changes

    return () => {
        // Optional; clean up when `count` changed
    };
}, [count]);

Trying to directly translating lifecycle hooks to useEffect calls is generally a bad idea. It’s better to rethink things as a set of declarative side effects. When the effect is called is an implementation detail.

尝试直接将生命周期挂钩转换为 useEffect 调用通常是一个坏主意。 最好把事情当作一系列宣示性的副作用来重新思考。 当调用效果时,是一个实现细节。

As Ryan Florence sums it up:

正如瑞安•弗洛伦斯(Ryan Florence)总结的:

The question is not “when does this effect run” the question is “with which state does this effect synchronize with”

问题不是"此效应何时运行",而是"此效应与哪个状态同步"

useEffect(fn) // all state
useEffect(fn, []) // no state
useEffect(fn, [these, states])

Useeffect (fn) / / all stateuseEffect (fn,[]) / no state useEffect (fn,[ these,states ])

@ryanflorence on Twitter

@ ryanflorence 在 Twitter 上

Watchers

守望者

React alternative: The useEffect hook

反应方式: 使用效果钩子

Watchers are conceptually similar to lifecycle hooks: “When X happens, do Y”. Watchers don’t exist in React, but you can achieve the same with useEffect.

观察者在概念上类似于生命周期挂钩:"当 x 发生时,做 y"。 观察者并不存在于反应中,但是你可以通过使用效果达到同样的效果。

<!-- AjaxToggle.vue -->

<template>
  <input type="checkbox" v-model="checked" />
</template>

<script>
export default {
  data() {
    return {
      checked: false
    }
  },

  watch: {
    checked(checked) {
      syncWithServer(checked);
    }
  },

  methods: {
    syncWithServer(checked) {
      // ...
    }
  }
};
</script>
import { useEffect, useState } from 'react';

export default function AjaxToggle() {
  const [checked, setChecked] = useState(false);

  function syncWithServer(checked) {
    // ...
  }

  useEffect(() => {
    syncWithServer(checked);
  }, [checked]);

  return (
    <input
      type="checkbox"
      checked={checked}
      onChange={() => setChecked(!checked)}
    />
  );
}

Note that useEffect will also run in the first render. This is the same as using the immediate parameter in a Vue watcher.

注意,useEffect 也会在第一次渲染中运行。 这与在 Vue 观察器中使用立即参数相同。

If you don’t want the effect to run on the first render, you’ll need to create a ref to store whether or not the first render has happened yet or not.

如果你不想让效果在第一次渲染时运行,你需要创建一个 ref 来存储第一次渲染是否已经发生。

import { useEffect, useRef, useState } from 'react';

export default function AjaxToggle() {
  const [checked, setChecked] = useState(false);
  const firstRender = useRef(true);

  function syncWithServer(checked) {
    // ...
  }

  useEffect(() => {
    if (firstRender.current) {
      firstRender.current = false;
      return;
    }
    syncWithServer(checked);
  }, [checked]);

  return (
    <input
      type="checkbox"
      checked={checked}
      onChange={() => setChecked(!checked)}
    />
  );
}

Slots & scoped slots

槽和作用域槽

React alternative: JSX props or render props

反应替代: JSX 道具或渲染道具

If you render a template inside between a component’s opening and closing tags, React passes it as a children prop.

如果在组件的开始标记和结束标记之间渲染一个模板,React 将其作为一个子标记传递给它。

With Vue, you need to declare a <slot /> tag where inner contents belong. With React, you render the children prop.

使用 Vue 时,您需要在内部内容所属的位置声明一个 slot / tag。 用反击,你给孩子们提供支持。

<!-- RedParagraph.vue -->

<template>
  <p style="color: red">
    <slot />
  </p>
</template>
export default function RedParagraph({ children }) {
  return (
    <p style={{ color: 'red' }}>
      {children}
    </p>
  );
}

Since “slots” are just props in React, we don’t need to declare anything in our templates. We can just accept props with JSX, and render them where and when we want.

因为"插槽"只是 React 中的道具,所以我们不需要在模板中声明任何东西。 我们可以使用 JSX 接受道具,然后在需要的时间和地点渲染它们。

<!-- Layout.vue -->

<template>
  <div class="flex">
    <section class="w-1/3">
        <slot name="sidebar" />
    </section>
    <main class="flex-1">
        <slot />
    </main>
  </div>
</template>

<!-- In use: -->

<layout>
  <template #sidebar>
    <nav>...</nav>
  </template>
  <template #default>
    <post>...</post>
  </template>
</layout>
export default function RedParagraph({ sidebar, children }) {
  return (
    <div className="flex">
      <section className="w-1/3">
        {sidebar}
      </section>
      <main className="flex-1">
        {children}
      </main>
    </div>
  );
}

// In use:

return (
  <Layout sidebar={<nav>...</nav>}>
    <Post>...</Post>
  </Layout>
);

Vue has scoped slots to pass data to the slot that will be rendered. The key part of scoped slots is will be rendered.

Vue 已经确定了狭槽的作用域,以便将数据传递给将要呈现的狭槽。 将呈现作用域狭槽的关键部分。

Regular slots are rendered before they get passed to the parent component. The parent component then decides what to do with the rendered fragment.

常规插槽在传递给父组件之前被呈现。 然后,父组件决定如何处理呈现的片段。

Scoped slots can’t be rendered before the parent component, because they rely on data they’ll receive from the parent component. In a way, scoped slots are lazily evaluated slots.

作用域插槽不能在父组件之前呈现,因为它们依赖于从父组件接收的数据。 在某种程度上,限定作用域的槽被延迟计算。

Lazily evaluating something in JavaScript is rather straightforward: wrap it in a function and call it when needed. If you need a scoped slot with React, pass a function that will render a template when called.

懒惰地在 JavaScript 中计算一些东西是相当直接的: 将它包装在一个函数中,并在需要时调用它。 如果需要使用 React 的作用域插槽,请传递一个函数,该函数将在调用时呈现模板。

For a scoped slots, we can once again use children, or any other prop for named scoped slots. However, we’ll pass down a function instead of declaring a template.

对于有作用域的狭槽,我们可以再次使用子狭槽或任何其他道具来命名有作用域的狭槽。 但是,我们将传递一个函数,而不是声明一个模板。

<!-- CurrentUser.vue -->

<template>
  <span>
    <slot :user="user" />
  </span>
</template>

<script>
export default {
  inject: ['user']
};
</script>

<!-- In use: -->

<template>
  <current-user>
    <template #default="{ user }">
      {{ user.firstName }}
    </template>
  </current-user>
</template>
import { useContext } from 'react';
import UserContext from './UserContext';

export default function CurrentUser({ children }) {
  const { user } = useContext(UserContext);

  return (
    <span>
      {children(user)}
    </span>
  );
}

// In use:

return (
  <CurrentUser>
    {user => user.firstName}
  </CurrentUser>
);

Provide / inject

提供 / 注入

React alternative: createContext and the useContext hook

反应替代: createContext 和 useContext 钩子

Provide / inject allows a component to share state with its subtree. React has a similar feature called context.

提供 / 注入允许组件与其子树共享状态。 有一个类似的特性叫做上下文。

<!-- MyProvider.vue -->

<template>
  <div><slot /></div>
</template>

<script>
export default {
  provide: {
    foo: 'bar'
  },
};
</script>

<!-- Must be rendered inside a MyProvider instance: -->

<template>
  <p>{{ foo }}</p>
</template>

<script>
export default {
  inject: ['foo']
};
</script>
import { createContext, useContext } from 'react';

const fooContext = createContext('foo');

function MyProvider({ children }) {
  return (
    <FooContext.Provider value="foo">
      {children}
    </FooContext.Provider>
  );
}

// Must be rendered inside a MyProvider instance:

function MyConsumer() {
  const foo = useContext(FooContext);

  return <p>{foo}</p>;
}

Custom directives

自定义指令

React alternative: Components

反应替代: 组件

Directives don’t exist in React. However, most problems that directives solve can be solved with components instead.

指令并不存在于反应中。 然而,指令解决的大多数问题都可以通过组件来解决。

<div v-tooltip="Hello!">
  <p>...</p>
</div>
return (
  <Tooltip text="Hello">
    <div>
      <p>...</p>
    </div>
  </Tooltip>
);

Transitions

过渡期

React alternative: Third party libraries

反应: 第三方库

React doesn’t have any built in transition utilities. If you’re looking for something similar to Vue, a library that doesn’t actually animates anything but orchestrates animations with classes, look into react-transition-group.

没有任何内置的转换工具。 如果您正在寻找与 Vue 类似的东西,那么您可以查看 react-transition-group,这个库实际上并不制作任何动画,而是用类编排动画。

原文

@ly2011 ly2011 added the 转载 label Jul 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant