zoukankan      html  css  js  c++  java
  • 数据驱动——组件

    原文链接:https://www.newline.co/fullstack-react/30-days-of-react/day-5/

    Data-Driven

    Hard-coding data in our applications isn't exactly ideal.

    Today, we'll set up our components to be driven by data to them access to external data.

    Through this point, we've written our first components and set them up in a child/parent relationship.

    However, we haven't yet tied any data to our React components. Although it's a more pleasant experience (in our opinion) writing a website in React, we haven't taken advantage of the power of React to display any dynamic data.

    Going data-driven

     We broke down our demo into components and ended up building three separate components with static JSX templates.

    It's not very convenient to have to update our component's template everytime we have a change in our website's data.

    Instead, let's give the components data to use to display.

    Let's start with the <Header /> component. As it stands right now, the <Header /> component only shows the title of the element as Timeline. It's a nice element and it would be nice to be able to reuse it in other parts of our page, but the title of Timeline doesn't make sense for every use.

    Let's tell React that we want to be able to set the title to something else.

    Introducing props

    React allows us to send data to a component in the same syntax as HTML, using attributes or properties on a component.

    This is akin to passing the src attribute to an image tag. We can think about the property of the <img /> tag as a prop we're setting on a component called img.

    We can access these properties inside a component as this.props. Let's see props in action.

    旧:

    class Header extends React.Component {
      render() {
        return (
          <div className="header">
            <div className="menuIcon">
              <div className="dashTop"></div>
              <div className="dashBottom"></div>
              <div className="circle"></div>
            </div>
            <span className="title">Timeline</span>
    
            <input
              type="text"
              className="searchInput"
              placeholder="Search ..." />
    
            <div className="fa fa-search searchIcon"></div>
          </div>
        )
      }
    }
    

    When we use the <Header /> component, we placed it in our <App /> component as like so:

    <Header />

    新:

    We can pass in our title as a prop as an attribute on the <Header /> by updating the usage of the component setting the attribute called title to some string, like so:

    <Header title="Timeline" />

    Inside of our component, we can access this title prop from the this.props property in the Header class. Instead of setting the title statically as Timeline in the template, we can replace it with the property passed in.

    class Header extends React.Component {
      render() {
        return (
          <div className="header">
            <div className="menuIcon">
              <div className="dashTop"></div>
              <div className="dashBottom"></div>
              <div className="circle"></div>
            </div>
    
            <span className="title">
              {this.props.title}
            </span>
    
            <input
              type="text"
              className="searchInput"
              placeholder="Search ..." />
    
            <div className="fa fa-search searchIcon"></div>
          </div>
        )
      }
    }
    

    We've also updated the code slightly to get closer to what our final <Header /> code will look like, including adding a searchIcon and a few elements to style the menuIcon.

    Now our <Header /> component will display the string we pass in as the title when we call the component. For instance, calling our <Header /> component four times like so:

    Now our <Header /> component will display the string we pass in as the title when we call the component. For instance, calling our <Header /> component four times like so:

    <Header title="Timeline" />
    <Header title="Profile" />
    <Header title="Settings" />
    <Header title="Chat" />
    

    Results in four <Header /> components to mount like so:

    Pretty nifty, ey? Now we can reuse the <Header /> component with a dynamic title property.

    We can pass in more than just strings in a component.

    We can pass in numbers, strings, all sorts of objects, and even functions!

    We'll talk more about how to define these different properties so we can build a component api later.

    Instead of statically setting the content and date let's take the Content component and set the timeline content by a data variable instead of by text.

    Just like we can do with HTML components, we can pass multiple props into a component

    旧:

    class Content extends React.Component {
      render() {
        return (
          <div className="content">
            <div className="line"></div>
    
          {/* Timeline item */}
            <div className="item">
              <div className="avatar">
                <img src="http://www.croop.cl/UI/twitter/images/doug.jpg" />
                Doug
              </div>
    
              <span className="time">
                An hour ago
              </span>
              <p>Ate lunch</p>
              <div className="commentCount">
                2
              </div>
            </div>
    
            {/* ... */}
    
          </div>
        )
      }
    }
    

    新:

    As we did with title, let's look at what props our Content component needs:

    • A user's avatar image
    • A timestamp of the activity
    • Text of the activity item
    • Number of comments

    Let's say that we have a JavaScript object that represents an activity item.

    We will have a few fields, such as a string field (text) and a date object. We might have some nested objects, like a user and comments. For instance:

    {
      timestamp: new Date().getTime(),
      text: "Ate lunch",
      user: {
        id: 1,
        name: 'Nate',
        avatar: "http://www.croop.cl/UI/twitter/images/doug.jpg"
      },
      comments: [
        { from: 'Ari', text: 'Me too!' }
      ]
    }
    

    Just like we passed in a string title to the <Header /> component, we can take this activity object and pass it right into the Content component.

    Let's convert our component to display the details from this activity inside it's template.

    In order to pass a dynamic variable's value into a template, we have to use the template syntax to render it in our template. For instance:

    In order to pass a dynamic variable's value into a template, we have to use the template syntax to render it in our template. For instance:

    class Content extends React.Component {
      render() {
        const {activity} = this.props; // ES6 destructuring
    
        return (
          <div className="content">
            <div className="line"></div>
    
            {/* Timeline item */}
            <div className="item">
              <div className="avatar">
                <img
                  alt={activity.text}
                  src={activity.user.avatar} />
                {activity.user.name}
              </div>
    
              <span className="time">
                {activity.timestamp}
              </span>
              <p>{activity.text}</p>
              <div className="commentCount">
                {activity.comments.length}
              </div>
            </div>
          </div>
        )
      }
    }

    We've use a little bit of ES6 in our class definition on the first line of the render() function called destructuring. The two following lines are functionally equivalent:

    // these lines do the same thing
    const activity = this.props.activity;
    const {activity} = this.props;
    

    Destructuring allows us to save on typing and define variables in a shorter, more compact way.

    We can then use this new content by passing in an object as a prop instead of a hard-coded string. For instance:

    <Content activity={moment1} />

     Fantastic, now we have our activity item driven by an object.

    However, you might have noticed that we would have to implement this multiple times with different comments.

    Instead, we could pass an array of objects into a component.

    Let's say we have an object that contains multiple activity items:

    const activities = [
      {
        timestamp: new Date().getTime(),
        text: "Ate lunch",
        user: {
          id: 1, name: 'Nate',
          avatar: "http://www.croop.cl/UI/twitter/images/doug.jpg"
        },
        comments: [{ from: 'Ari', text: 'Me too!' }]
      },
      {
        timestamp: new Date().getTime(),
        text: "Woke up early for a beautiful run",
        user: {
          id: 2, name: 'Ari',
          avatar: "http://www.croop.cl/UI/twitter/images/doug.jpg"
        },
        comments: [{ from: 'Nate', text: 'I am so jealous' }]
      },
    ]

    We can rearticulate our usage of <Content /> by passing in multiple activities instead of just one:

    <Content activities={activities} />
    

    However, if we refresh the view nothing will show up!

    We need to first update our Content component to accept multiple activities.

    As we learned about previously, JSX is really just JavaScript executed by the browser. We can execute JavaScript functions inside the JSX content as it will just get run by the browser like the rest of our JavaScript.

    Let's move our activity item JSX inside of the function of the map function that we'll run over for every item.

    class Content extends React.Component {
      render() {
        const {activities} = this.props; // ES6 destructuring
    
        return (
          <div className="content">
            <div className="line"></div>
    
            {/* Timeline item */}
            {activities.map((activity) => {
              return (
                <div className="item">
                  <div className="avatar">
                    <img
                      alt={activity.text}
                      src={activity.user.avatar} />
                    {activity.user.name}
                  </div>
    
                  <span className="time">
                    {activity.timestamp}
                  </span>
                  <p>{activity.text}</p>
                  <div className="commentCount">
                    {activity.comments.length}
                  </div>
                </div>
              );
            })}
    
          </div>
        )
      }
    }

     Now we can pass any number of activities to our array and the Content component will handle it,

    however if we leave the component right now, then we'll have a relatively complex component handling both containing and displaying a list of activities.Leaving it like this really isn't the React way.

    ActivityItem

    Here is where it makes sense to write one more component to contain displaying a single activity item and then rather than building a complex Content component,

    we can move the responsibility.

    This will also make it easier to test, add functionality, etc.

    Let's update our Content component to display a list of ActivityItem components (we'll create this next).

    class Content extends React.Component {
      render() {
        const {activities} = this.props; // ES6 destructuring
    
        return (
          <div className="content">
            <div className="line"></div>
    
            {/* Timeline item */}
            {activities.map((activity) => (
              <ActivityItem
                activity={activity} />
            ))}
    
          </div>
        )
      }
    }

    Not only is this much simpler and easier to understand, but it makes testing both components easier.

    With our freshly-minted Content component, let's create the ActivityItem component.

    Since we already have the view created for the ActivityItem, all we need to do is copy it from what was our Content component's template as it's own module.

    class ActivityItem extends React.Component {
      render() {
        const {activity} = this.props; // ES6 destructuring
    
        return (
          <div className="item">
            <div className="avatar">
              <img
                alt={activity.text}
                src={activity.user.avatar} />
              {activity.user.name}
            </div>
    
            <span className="time">
              {activity.timestamp}
            </span>
            <p>{activity.text}</p>
            <div className="commentCount">
              {activity.comments.length}
            </div>
          </div>
        )
      }
    }

    This week we updated our components to be driven by data by using the React props concept.

  • 相关阅读:
    Spring Cloud (八):服务调用追踪 sleuth & zipkin
    Spring Cloud (七):API 网关
    Spring Cloud (六):声明式 REST 请求 Feign
    maven 下载 jar 包到本地
    K8S 设置 Pod 使用 host 网络、配置 DNS
    Spring Cloud (五):容错处理 Hystrix
    Spring Cloud (四):客户端实现负载均衡
    [数仓]数据仓库设计方案
    [知识图谱]Neo4j知识图谱构建(neo4j-python-pandas-py2neo-v3)
    [Pandas]利用Pandas处理excel数据
  • 原文地址:https://www.cnblogs.com/panpanwelcome/p/12358094.html
Copyright © 2011-2022 走看看