กลยุทธ์สำหรับการแสดงผลฝั่งเซิร์ฟเวอร์ของคอมโพเนนต์ React.js ที่เตรียมใช้งานแบบอะซิงโครนัส


114

หนึ่งในข้อได้เปรียบที่ใหญ่ที่สุดของReact.jsควรจะเป็นการแสดงผลด้านเซิร์ฟเวอร์ ปัญหาคือฟังก์ชันคีย์React.renderComponentToString()เป็นแบบซิงโครนัสซึ่งทำให้ไม่สามารถโหลดข้อมูลอะซิงโครนัสใด ๆ ได้เนื่องจากลำดับชั้นของคอมโพเนนต์แสดงบนเซิร์ฟเวอร์

สมมติว่าฉันมีองค์ประกอบสากลสำหรับการแสดงความคิดเห็นซึ่งฉันสามารถวางไว้ที่ใดก็ได้บนหน้า มีเพียงคุณสมบัติเดียวตัวระบุบางประเภท (เช่น id ของบทความด้านล่างที่มีการใส่ความคิดเห็น) และทุกอย่างจะถูกจัดการโดยคอมโพเนนต์เอง (การโหลดการเพิ่มการจัดการความคิดเห็น)

ฉันชอบสถาปัตยกรรมFluxมากเพราะมันทำให้หลาย ๆ อย่างง่ายขึ้นมากและร้านค้าก็เหมาะสำหรับการแชร์สถานะระหว่างเซิร์ฟเวอร์และไคลเอนต์ เมื่อเริ่มต้นร้านค้าของฉันที่มีความคิดเห็นแล้วฉันก็สามารถทำให้เป็นซีเรียลไลซ์และส่งจากเซิร์ฟเวอร์ไปยังไคลเอนต์ซึ่งเรียกคืนได้อย่างง่ายดาย

คำถามคือวิธีใดเป็นวิธีที่ดีที่สุดในการเติมข้อมูลร้านค้าของฉัน ในช่วงหลายวันที่ผ่านมาฉัน Googling มากและฉันเจอกลยุทธ์บางอย่างซึ่งดูเหมือนจะไม่ดีเลยเมื่อพิจารณาว่าคุณสมบัติของ React นี้ได้รับการ "โปรโมต" มากแค่ไหน

  1. ในความคิดของฉันวิธีที่ง่ายที่สุดคือเติมข้อมูลร้านค้าทั้งหมดของฉันก่อนที่การแสดงผลจริงจะเริ่มขึ้น นั่นหมายถึงบางแห่งที่อยู่นอกลำดับชั้นของส่วนประกอบ (เช่นต่อกับเราเตอร์ของฉัน) ปัญหาของวิธีนี้คือฉันจะต้องกำหนดโครงสร้างหน้าสองครั้ง พิจารณาหน้าเว็บที่ซับซ้อนมากขึ้นตัวอย่างเช่นหน้าบล็อกที่มีส่วนประกอบต่างๆมากมาย (โพสต์ในบล็อกจริงความคิดเห็นโพสต์ที่เกี่ยวข้องโพสต์ใหม่ล่าสุดกระแส Twitter ... ) ฉันจะต้องออกแบบโครงสร้างเพจโดยใช้ส่วนประกอบ React จากนั้นที่อื่นฉันจะต้องกำหนดขั้นตอนการเติมข้อมูลแต่ละร้านที่ต้องการสำหรับเพจปัจจุบันนี้ ดูเหมือนจะไม่ใช่ทางออกที่ดีสำหรับฉัน น่าเสียดายที่แบบฝึกหัด isomorphic ส่วนใหญ่ได้รับการออกแบบด้วยวิธีนี้ (เช่นการสอนเกี่ยวกับฟลักซ์ที่ยอดเยี่ยมนี้)

  2. ตอบสนอง-async แนวทางนี้เหมาะอย่างยิ่ง ช่วยให้ฉันกำหนดฟังก์ชันพิเศษในแต่ละองค์ประกอบว่าจะเริ่มต้นสถานะอย่างไร (ไม่สำคัญว่าจะซิงโครนัสหรืออะซิงโครนัส) และฟังก์ชันเหล่านี้เรียกว่าลำดับชั้นกำลังแสดงผลเป็น HTML มันทำงานในลักษณะที่ส่วนประกอบจะไม่แสดงผลจนกว่าสถานะจะเริ่มต้นอย่างสมบูรณ์ ปัญหาคือมันต้องใช้Fibersซึ่งเท่าที่ฉันเข้าใจส่วนขยาย Node.js ที่เปลี่ยนแปลงพฤติกรรม JavaScript มาตรฐาน แม้ว่าฉันจะชอบผลลัพธ์มาก แต่ก็ยังดูเหมือนว่าสำหรับฉันแทนที่จะหาวิธีแก้ปัญหาเราเปลี่ยนกฎของเกม และฉันคิดว่าเราไม่ควรถูกบังคับให้ทำเช่นนั้นเพื่อใช้คุณสมบัติหลักของ React.js ฉันยังไม่แน่ใจเกี่ยวกับการสนับสนุนทั่วไปของโซลูชันนี้ เป็นไปได้ไหมที่จะใช้ Fiber บนเว็บโฮสติ้ง Node.js มาตรฐาน

  3. ฉันกำลังคิดเล็กน้อยด้วยตัวเอง ฉันไม่ได้คิดถึงรายละเอียดการใช้งานจริง ๆ แต่แนวคิดทั่วไปคือฉันจะขยายส่วนประกอบในลักษณะเดียวกันกับ React-async จากนั้นฉันจะเรียก React.renderComponentToString () ซ้ำ ๆ บนองค์ประกอบราก ในแต่ละรอบฉันจะรวบรวมการโทรกลับที่ขยายออกแล้วโทรหาพวกเขาที่และของบัตรเพื่อเติมข้อมูลร้านค้า ฉันจะทำขั้นตอนนี้ซ้ำจนกว่าร้านค้าทั้งหมดที่ต้องการตามลำดับชั้นของส่วนประกอบปัจจุบันจะถูกเติม มีหลายสิ่งที่ต้องแก้ไขและฉันไม่แน่ใจเป็นพิเศษเกี่ยวกับประสิทธิภาพ

ฉันพลาดอะไรไปหรือเปล่า? มีแนวทาง / แนวทางแก้ไขอื่นหรือไม่? ตอนนี้ฉันกำลังคิดที่จะใช้วิธี react-async / fibre แต่ฉันไม่แน่ใจอย่างสมบูรณ์ตามที่อธิบายไว้ในจุดที่สอง

การอภิปรายที่เกี่ยวข้องบน GitHub เห็นได้ชัดว่าไม่มีแนวทางอย่างเป็นทางการหรือแม้แต่วิธีแก้ปัญหา อาจจะเป็นคำถามที่แท้จริงว่าส่วนประกอบของ React มีไว้เพื่อใช้งานอย่างไร เช่นเดียวกับเลเยอร์มุมมองที่เรียบง่าย (ข้อเสนอแนะของฉันอันดับหนึ่ง) หรือชอบส่วนประกอบอิสระและแบบสแตนด์อโลนที่แท้จริง?


เพื่อรับสิ่งต่างๆ: การโทรแบบอะซิงโครนัสจะเกิดขึ้นที่ฝั่งเซิร์ฟเวอร์ด้วยหรือไม่? ฉันไม่เข้าใจประโยชน์ในกรณีนี้เมื่อเทียบกับการแสดงผลมุมมองโดยปล่อยให้บางส่วนว่างเปล่าและกรอกข้อมูลเมื่อผลลัพธ์จากการตอบกลับแบบอะซิงโครนัสมาถึง อาจจะขาดอะไรไปขออภัย!
phtrivier

คุณต้องไม่ลืมว่าใน JavaScript แม้แต่แบบสอบถามที่ง่ายที่สุดในฐานข้อมูลเพื่อดึงโพสต์ล่าสุดก็ยังไม่ตรงกัน ดังนั้นหากคุณกำลังแสดงมุมมองคุณต้องรอจนกว่าจะดึงข้อมูลจากฐานข้อมูล และมีประโยชน์ที่ชัดเจนในการแสดงผลบนฝั่งเซิร์ฟเวอร์เช่น SEO และยังป้องกันไม่ให้หน้ากะพริบอีกด้วย การแสดงผลฝั่งเซิร์ฟเวอร์เป็นแนวทางมาตรฐานที่เว็บไซต์ส่วนใหญ่ยังคงใช้อยู่
Tobik

แน่นอน แต่คุณกำลังพยายามแสดงผลทั้งหน้า (เมื่อตอบแบบสอบถาม db แบบอะซิงโครนัสทั้งหมดแล้ว) ในกรณีนี้ฉันจะแยกมันอย่างไร้เดียงสาเป็น 1 / ดึงข้อมูลทั้งหมดแบบอะซิงโครนัส 2 / เมื่อเสร็จแล้วให้ส่งต่อไปยังมุมมองการตอบสนองที่ "โง่" และตอบกลับคำขอ หรือคุณกำลังพยายามทำการแสดงผลทั้งฝั่งเซิร์ฟเวอร์จากนั้นฝั่งไคลเอ็นต์ด้วยรหัสเดียวกัน (และคุณต้องการรหัส async เพื่อให้ใกล้เคียงกับมุมมองการตอบสนองหรือไม่) ขออภัยหากฟังดูงี่เง่าฉันไม่แน่ใจว่าจะได้รับ คุณกำลังทำอะไรอยู่
phtrivier

ไม่มีปัญหาบางทีคนอื่นอาจมีปัญหาในการทำความเข้าใจ :) สิ่งที่คุณเพิ่งอธิบายคือวิธีแก้ปัญหาข้อที่สอง แต่ยกตัวอย่างส่วนประกอบสำหรับแสดงความคิดเห็นจากคำถาม ในแอปพลิเคชันฝั่งไคลเอ็นต์ทั่วไปฉันสามารถทำทุกอย่างในองค์ประกอบนั้นได้ (โหลด / เพิ่มความคิดเห็น) ส่วนประกอบจะแยกออกจากโลกภายนอกและโลกภายนอกก็ไม่ต้องสนใจส่วนประกอบนี้ มันจะเป็นอิสระอย่างสมบูรณ์และเป็นแบบสแตนด์อโลน แต่เมื่อฉันต้องการแนะนำการแสดงผลฝั่งเซิร์ฟเวอร์ฉันต้องจัดการกับสิ่งที่ไม่ซิงโครนัสภายนอก และนั่นทำลายหลักการทั้งหมด
Tobik

เพื่อความชัดเจนฉันไม่ได้สนับสนุนการใช้เส้นใย แต่เพียงแค่ทำการเรียก asyncs ทั้งหมดและหลังจากเสร็จสิ้นทั้งหมด (โดยใช้สัญญาหรืออะไรก็ตาม) ให้แสดงผลส่วนประกอบที่ฝั่งเซิร์ฟเวอร์ (ดังนั้นส่วนประกอบการตอบสนองจะไม่ทราบเลยเกี่ยวกับสิ่งที่ไม่ตรงกัน) ตอนนี้เป็นเพียงความเห็น แต่จริงๆแล้วฉันชอบแนวคิดในการลบสิ่งที่เกี่ยวข้องกับการสื่อสารของเซิร์ฟเวอร์ออกจากส่วนประกอบการตอบสนองอย่างสมบูรณ์ (ซึ่งมีอยู่ที่นี่เท่านั้นเพื่อแสดงมุมมอง .) และฉันคิดว่านั่นคือปรัชญาเบื้องหลังการตอบสนองซึ่งอาจอธิบายได้ว่าทำไมสิ่งที่คุณทำจึงซับซ้อนเล็กน้อย ยังไงก็ขอให้โชคดี :)
phtrivier

คำตอบ:


15

หากคุณใช้react-routerคุณสามารถกำหนดwillTransitionToวิธีการในส่วนประกอบซึ่งจะส่งผ่านTransitionวัตถุที่คุณสามารถเรียก.waitใช้ได้

ไม่สำคัญว่า renderToString จะซิงโครนัสหรือไม่เนื่องจากการโทรกลับไปยังRouter.runจะไม่ถูกเรียกจนกว่า.waitสัญญา ed ทั้งหมดจะได้รับการแก้ไขดังนั้นเมื่อถึงเวลาที่renderToStringเรียกว่ามิดเดิลแวร์คุณสามารถเติมข้อมูลร้านค้าได้ แม้ว่าร้านค้าจะเป็น singletons คุณก็สามารถตั้งค่าข้อมูลของพวกเขาได้ในเวลาเพียงชั่วคราวก่อนที่จะมีการเรียกใช้การแสดงผลแบบซิงโครนัสและส่วนประกอบจะเห็น

ตัวอย่างมิดเดิลแวร์:

var Router = require('react-router');
var React = require("react");
var url = require("fast-url-parser");

module.exports = function(routes) {
    return function(req, res, next) {
        var path = url.parse(req.url).pathname;
        if (/^\/?api/i.test(path)) {
            return next();
        }
        Router.run(routes, path, function(Handler, state) {
            var markup = React.renderToString(<Handler routerState={state} />);
            var locals = {markup: markup};
            res.render("layouts/main", locals);
        });
    };
};

routesวัตถุ (ซึ่งอธิบายถึงลำดับชั้นของเส้นทาง) ที่ใช้ร่วมกันคำต่อคำกับลูกค้าและเซิร์ฟเวอร์


ขอบคุณ สิ่งนี้ก็คือเท่าที่ฉันรู้มีเพียงส่วนประกอบของเส้นทางเท่านั้นที่รองรับwillTransitionToวิธีนี้ ซึ่งหมายความว่ายังไม่สามารถเขียนส่วนประกอบที่ใช้ซ้ำได้แบบสแตนด์อโลนอย่างสมบูรณ์เหมือนที่ฉันอธิบายไว้ในคำถาม แต่ถ้าเราไม่เต็มใจที่จะใช้ Fibers นี่อาจเป็นวิธีที่ดีที่สุดและตอบสนองได้ดีที่สุดในการใช้การแสดงผลฝั่งเซิร์ฟเวอร์
Tobik

นี่เป็นเรื่องที่น่าสนใจ การนำเมธอด willTransitionTo ไปใช้งานจะมีลักษณะอย่างไรเมื่อโหลดข้อมูล async
Hyra

คุณจะได้รับวัตถุเป็นพารามิเตอร์ดังนั้นคุณก็จะเรียกtransition transition.wait(yourPromise)แน่นอนว่าคุณต้องใช้ API ของคุณเพื่อรองรับคำสัญญา ข้อเสียอีกประการหนึ่งของแนวทางนี้คือไม่มีวิธีง่ายๆในการติดตั้ง "ตัวบ่งชี้การโหลด" ในฝั่งไคลเอ็นต์ การเปลี่ยนจะไม่เปลี่ยนไปใช้องค์ประกอบตัวจัดการเส้นทางจนกว่าคำสัญญาทั้งหมดจะได้รับการแก้ไข
Tobik

แต่จริงๆแล้วฉันไม่แน่ใจเกี่ยวกับแนวทาง "ทันเวลา" ตัวจัดการเส้นทางที่ซ้อนกันหลายตัวสามารถจับคู่ URL เดียวซึ่งหมายความว่าจะต้องมีการแก้ไขสัญญาหลายฉบับ ไม่มีการรับประกันว่าทั้งหมดจะจบลงในเวลาเดียวกัน หากร้านค้าเป็นร้านเดี่ยวอาจทำให้เกิดความขัดแย้งได้ @Esailija คุณช่วยอธิบายคำตอบของคุณหน่อยได้ไหม?
Tobik

ฉันมีระบบประปาอัตโนมัติที่รวบรวมสัญญาทั้งหมด.waitedสำหรับการเปลี่ยนแปลง เมื่อครบทั้งหมดแล้วจะมีการ.runโทรกลับ ก่อนที่.render()ฉันจะรวบรวมข้อมูลทั้งหมดเข้าด้วยกันจากสัญญาและตั้งค่าสถานะการจัดเก็บ singelton จากนั้นในบรรทัดถัดไปหลังจากการเรียกใช้การแสดงผลฉันเริ่มต้นการจัดเก็บซิงเกิลตันกลับมา มันค่อนข้างแฮ็ค แต่ทั้งหมดเกิดขึ้นโดยอัตโนมัติและส่วนประกอบและรหัสแอปพลิเคชันร้านค้ายังคงเหมือนเดิม
Esailija

0

ฉันรู้ว่านี่อาจไม่ใช่สิ่งที่คุณต้องการอย่างแน่นอนและอาจไม่สมเหตุสมผล แต่ฉันจำได้ว่าการปรับเปลี่ยนองค์ประกอบเพื่อจัดการทั้งสองอย่างนี้:

  • การแสดงผลบนฝั่งเซิร์ฟเวอร์โดยมีการดึงสถานะเริ่มต้นทั้งหมดแล้วแบบอะซิงโครนัสหากจำเป็น)
  • การแสดงผลบนฝั่งไคลเอ็นต์โดยใช้ ajax หากจำเป็น

สิ่งที่ชอบ:

/** @jsx React.DOM */

var UserGist = React.createClass({
  getInitialState: function() {

    if (this.props.serverSide) {
       return this.props.initialState;
    } else {
      return {
        username: '',
        lastGistUrl: ''
      };
    }

  },

  componentDidMount: function() {
    if (!this.props.serverSide) {

     $.get(this.props.source, function(result) {
      var lastGist = result[0];
      if (this.isMounted()) {
        this.setState({
          username: lastGist.owner.login,
          lastGistUrl: lastGist.html_url
        });
      }
    }.bind(this));

    }

  },

  render: function() {
    return (
      <div>
        {this.state.username}'s last gist is
        <a href={this.state.lastGistUrl}>here</a>.
      </div>
    );
  }
});

// On the client side
React.renderComponent(
  <UserGist source="https://api.github.com/users/octocat/gists" />,
  mountNode
);

// On the server side
getTheInitialState().then(function (initialState) {

    var renderingOptions = {
        initialState : initialState;
        serverSide : true;
    };
    var str = Xxx.renderComponentAsString( ... renderingOptions ...)  

});

ฉันขอโทษฉันไม่มีรหัสที่แน่นอนอยู่ในมือดังนั้นอาจไม่ได้ผล แต่ฉันโพสต์เพื่อให้เกิดความสนใจ

อีกครั้งแนวคิดคือการปฏิบัติต่อองค์ประกอบส่วนใหญ่เป็นมุมมองที่โง่เขลาและจัดการกับการดึงข้อมูลออกจากส่วนประกอบให้มากที่สุด


1
ขอบคุณ. ฉันเข้าใจ แต่มันไม่ใช่สิ่งที่ฉันต้องการจริงๆ สมมติว่าผมต้องการที่จะสร้างบางเว็บไซต์ที่ซับซ้อนมากขึ้นโดยใช้ตอบสนองเช่นbbc.com เมื่อมองไปที่หน้าฉันสามารถเห็น "ส่วนประกอบ" ได้ทุกที่ ส่วน (กีฬาธุรกิจ ... ) เป็นส่วนประกอบทั่วไป คุณจะใช้มันอย่างไร? คุณจะดึงข้อมูลทั้งหมดไว้ที่ใด ในการออกแบบไซต์ที่ซับซ้อนเช่นนี้ส่วนประกอบ (ตามหลักการเช่นตู้คอนเทนเนอร์ MVC ขนาดเล็ก) เป็นวิธีที่ดีมาก (ถ้าอาจเป็นวิธีเดียว) วิธีการคอมโพเนนต์เป็นเรื่องปกติสำหรับเฟรมเวิร์กฝั่งเซิร์ฟเวอร์ทั่วไป คำถามคือฉันสามารถใช้ React ได้หรือไม่?
Tobik

คุณจะดึงข้อมูลล่วงหน้าทางฝั่งเซิร์ฟเวอร์ (ซึ่งอาจทำในกรณีนี้ก่อนที่จะส่งต่อไปยังระบบเทมเพลตฝั่งเซิร์ฟเวอร์ "แบบดั้งเดิม") เพียงเพราะการแสดงผลของข้อมูลได้รับประโยชน์จากการเป็นโมดูลาร์มันหมายความว่าการคำนวณของข้อมูลจำเป็นต้องเป็นไปตามโครงสร้างเดียวกันหรือไม่? ฉันกำลังเล่น Devil's Advocate อยู่ที่นี่ฉันมีปัญหาเดียวกันกับที่คุณมีเมื่อตรวจสอบ om และฉันแน่ใจว่าใครบางคนจะมีข้อมูลเชิงลึกเกี่ยวกับเรื่องนี้มากกว่านี้ - การเขียนสิ่งต่างๆที่ด้านใดด้านหนึ่งของลวดอย่างราบรื่นจะช่วยได้มาก
phtrivier

1
โดยที่ฉันหมายถึงที่ไหนในรหัส ในตัวควบคุม? ดังนั้นวิธีการควบคุมที่จัดการโฮมเพจของ bbc จะมีข้อความค้นหาที่คล้ายกันหลายสิบข้อความสำหรับแต่ละส่วน? นั่นคือหนทางสู่นรก ดังนั้นใช่ฉันทำคิดคำนวณที่ควรจะเป็นแบบแยกส่วนเช่นกัน ทุกอย่างบรรจุในส่วนประกอบเดียวในคอนเทนเนอร์ MVC เดียว นั่นเป็นวิธีที่ฉันพัฒนาแอพฝั่งเซิร์ฟเวอร์มาตรฐานและฉันค่อนข้างมั่นใจว่าแนวทางนี้ดี และเหตุผลที่ฉันรู้สึกตื่นเต้นกับ React.js มากก็คือมีศักยภาพที่ดีในการใช้แนวทางนี้ทั้งในฝั่งไคลเอ็นต์และเซิร์ฟเวอร์เพื่อสร้างแอป isomorphic ที่ยอดเยี่ยม
Tobik

1
ในไซต์ใด ๆ (ใหญ่ / เล็ก) คุณต้องแสดงผลฝั่งเซิร์ฟเวอร์ (SSR) เฉพาะเพจปัจจุบันที่มีสถานะเริ่มต้น คุณไม่จำเป็นต้องมีสถานะเริ่มต้นสำหรับทุกหน้า เซิร์ฟเวอร์คว้ารัฐ init, วาทกรรมที่มันและผ่านมันไปยังลูกค้า<script type=application/json>{initState}</script>; ด้วยวิธีนี้ข้อมูลจะอยู่ใน HTML rehydrate / ผูกเหตุการณ์ UI กับเพจโดยเรียก render บนไคลเอนต์ เพจต่อมาถูกสร้างโดยโค้ด js ของไคลเอนต์ (ดึงข้อมูลตามต้องการ) และแสดงผลโดยไคลเอนต์ ด้วยวิธีนี้การรีเฟรชใด ๆ จะโหลดหน้า SSR ใหม่และการคลิกบนเพจจะเป็น CSR = isomorphic & SEO friendly
Federico

0

วันนี้ฉันยุ่งมากกับเรื่องนี้และแม้ว่านี่จะไม่ใช่คำตอบสำหรับปัญหาของคุณ แต่ฉันก็ใช้วิธีนี้ ฉันต้องการใช้ Express ในการกำหนดเส้นทางแทน React Router และฉันไม่ต้องการใช้ Fibers เพราะฉันไม่ต้องการการรองรับเธรดในโหนด

ดังนั้นฉันเพิ่งตัดสินใจว่าสำหรับข้อมูลเริ่มต้นที่ต้องแสดงผลไปยังที่เก็บฟลักซ์เมื่อโหลดฉันจะดำเนินการตามคำขอ AJAX และส่งข้อมูลเริ่มต้นไปยังที่เก็บ

ฉันใช้ Fluxxor สำหรับตัวอย่างนี้

ดังนั้นบนเส้นทางด่วนของฉันในกรณีนี้คือ/productsเส้นทาง:

var request = require('superagent');
var url = 'http://myendpoint/api/product?category=FI';

request
  .get(url)
  .end(function(err, response){
    if (response.ok) {    
      render(res, response.body);        
    } else {
      render(res, 'error getting initial product data');
    }
 }.bind(this));

จากนั้นเริ่มต้นวิธีการเรนเดอร์ของฉันซึ่งส่งข้อมูลไปยังร้านค้า

var render = function (res, products) {
  var stores = { 
    productStore: new productStore({category: category, products: products }),
    categoryStore: new categoryStore()
  };

  var actions = { 
    productActions: productActions,
    categoryActions: categoryActions
  };

  var flux = new Fluxxor.Flux(stores, actions);

  var App = React.createClass({
    render: function() {
      return (
          <Product flux={flux} />
      );
    }
  });

  var ProductApp = React.createFactory(App);
  var html = React.renderToString(ProductApp());
  // using ejs for templating here, could use something else
  res.render('product-view.ejs', { app: html });

0

ฉันรู้ว่าคำถามนี้ถูกถามเมื่อปีที่แล้ว แต่เรามีปัญหาเดียวกันและเราแก้ปัญหาด้วยคำสัญญาซ้อนที่ได้มาจากส่วนประกอบที่กำลังจะแสดงผล ในที่สุดเราก็มีข้อมูลทั้งหมดสำหรับแอปและส่งไปตามทาง

ตัวอย่างเช่น:

var App = React.createClass({

    /**
     *
     */
    statics: {
        /**
         *
         * @returns {*}
         */
        getData: function (t, user) {

            return Q.all([

                Feed.getData(t),

                Header.getData(user),

                Footer.getData()

            ]).spread(
                /**
                 *
                 * @param feedData
                 * @param headerData
                 * @param footerData
                 */
                function (feedData, headerData, footerData) {

                    return {
                        header: headerData,
                        feed: feedData,
                        footer: footerData
                    }

                });

        }
    },

    /**
     *
     * @returns {XML}
     */
    render: function () {

        return (
            <label>
                <Header data={this.props.header} />
                <Feed data={this.props.feed}/>
                <Footer data={this.props.footer} />
            </label>
        );

    }

});

และในเราเตอร์

var AppFactory = React.createFactory(App);

App.getData(t, user).then(
    /**
     *
     * @param data
     */
    function (data) {

        var app = React.renderToString(
            AppFactory(data)
        );       

        res.render(
            'layout',
            {
                body: app,
                someData: JSON.stringify(data)                
            }
        );

    }
).fail(
    /**
     *
     * @param error
     */
    function (error) {
        next(error);
    }
);

0

อยากแบ่งปันวิธีการใช้การเรนเดอร์ฝั่งเซิร์ฟเวอร์ของฉันกับคุณFluxตัวอย่างเช่น:

  1. สมมติว่าเรามีcomponentข้อมูลเริ่มต้นจากร้านค้า:

    class MyComponent extends Component {
      constructor(props) {
        super(props);
        this.state = {
          data: myStore.getData()
        };
      }
    }
  2. หากคลาสต้องการข้อมูลที่โหลดไว้ล่วงหน้าสำหรับสถานะเริ่มต้นให้สร้าง Loader สำหรับMyComponent:

     class MyComponentLoader {
        constructor() {
            myStore.addChangeListener(this.onFetch);
        }
        load() {
            return new Promise((resolve, reject) => {
                this.resolve = resolve;
                myActions.getInitialData(); 
            });
        }
        onFetch = () => this.resolve(data);
    }
  3. เก็บ:

    class MyStore extends StoreBase {
        constructor() {
            switch(action => {
                case 'GET_INITIAL_DATA':
                this.yourFetchFunction()
                    .then(response => {
                        this.data = response;
                        this.emitChange();
                     });
                 break;
        }
        getData = () => this.data;
    }
  4. ตอนนี้เพียงแค่โหลดข้อมูลในเราเตอร์:

    on('/my-route', async () => {
        await new MyComponentLoader().load();
        return <MyComponent/>;
    });

0

เช่นเดียวกับค่าสะสมสั้น ๆ -> GraphQL จะแก้ปัญหานี้ให้กับสแต็กของคุณ ...

  • เพิ่ม GraphQL
  • ใช้ apollo และ react-apollo
  • ใช้ "getDataFromTree" ก่อนเริ่มการแสดงผล

-> getDataFromTree จะค้นหาคำค้นหาที่เกี่ยวข้องทั้งหมดในแอปของคุณโดยอัตโนมัติและดำเนินการเหล่านั้นโดยใส่แคชอพอลโลของคุณบนเซิร์ฟเวอร์และทำให้ SSR ทำงานได้อย่างเต็มที่ .. BÄM

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.