简体   繁体   English

在 ReactJS 中按一个共享字段(整数)对不同对象的多个 arrays 进行排序?

[英]sort multiple arrays of different objects by one shared field (integer) in ReactJS?

I have an object (Page) with multiple different nested objects (Question, Image, Text, Video, etc.) that all have the same property (number) served up as JSON from Ruby on Rails我有一个 object(页面),其中包含多个不同的嵌套对象(问题、图像、文本、视频等),它们都具有相同的属性(数字),从 Rails 上的 Ruby 提供为 JSON

render :json => @page, :include => [:videos, :images, :rtfs, questions: { :include => :answers }]   

How can I display all this content sorted by the number property?如何显示按数字属性排序的所有这些内容? I can easily map through page.images , page.videos , etc. and display those in the correct respective order as they are ordered by number field in RoR already, but that only gets me so far.我可以轻松地通过page.imagespage.videos等 map 并以正确的顺序显示它们,因为它们已经按 RoR 中的数字字段排序,但这只能让我到目前为止。 Let's say the page has 2 questions (with numbers 2 and 4), 1 video (number 3), 1 image (number 1) and no rtf's.假设该页面有 2 个问题(编号 2 和 4)、1 个视频(编号 3)、1 张图像(编号 1)并且没有 rtf。 For now I am simply mapping through videos first and rendering them, then images, then questions, then rtf's.现在我只是先映射视频并渲染它们,然后是图像,然后是问题,然后是 rtf。 But what I need is to do in this particular case is to have the image displayed first (since it's number property is 1), then one of the questions (with number property 2), then video (since it's number 3) and finally, the other question.但是在这种特殊情况下我需要做的是首先显示图像(因为它的数字属性是 1),然后是其中一个问题(数字属性是 2),然后是视频(因为它是数字 3),最后,另一个问题。 I feel like I need to create separate arrays for all the nested object types ( videos, images, questions , etc.), then merge them (using a splat operator, most likely) into a single array called page_data , sort it by number field and then render it.我觉得我需要为所有嵌套的 object 类型( videos, images, questions等)创建单独的 arrays,然后将它们合并(很可能使用 splat 运算符)到一个名为page_data的数组中,按数字字段排序然后渲染它。 As I am still quite new to coding, I am having a hard time figuring it out and would appreciate any help!由于我对编码还很陌生,所以我很难弄明白,希望得到任何帮助! Here are the relevant parts of the React Component下面是 React Component 的相关部分

class LessonCreatorPage extends Component {constructor(props) {
super(props);
this.state = {
  page_preview: {}, //this is the main object that has different types of nested objects
}}
showPage(id){
//returns the response from backend and passes it to page_preview object 
}
  };
render(){
   {this.state.page_preview && (
            React.Fragment>

the snippet below is repeated for this.state.page_preview.images, questions, rtf's.下面的代码片段针对 this.state.page_preview.images、问题、rtf 重复。 They all are displayed in a different manner它们都以不同的方式显示

 {this.state.page_preview.videos && (
                <React.Fragment>
                  {this.state.page_preview.videos.map((video) =>{
                    const video_id = `${video.vimeo_id}`;
                    return (
                      <React.Fragment key={video.id}>
                        <Label pointing="below">{video.title}</Label>

                        <Embed id={video_id} source="vimeo" />
                        <Label pointing>{video.description}</Label>
                      </React.Fragment>
                    );
                  })}
                </React.Fragment>
              )}
            </React.Fragment>
          )}

I feel like I need to create separate arrays for all the nested object types ( videos , images , questions , etc.), then merge them (using a splat operator, most likely) into a single array called page_data , sort it by number field and then render it.我觉得我需要为所有嵌套的 object 类型( videosimagesquestions等)创建单独的 arrays,然后将它们合并(很可能使用 splat 运算符)到一个名为page_data的数组中,按数字字段排序然后渲染它。

You are on the correct path.你走在正确的道路上。 There is no reason to do this on the server though.但是没有理由在服务器上执行此操作。 You are requesting JSON and you have the question tagged with so I'll assume the data will be delivered there.您正在请求 JSON,并且您的问题已标记为 ,因此我假设数据将传送到那里。

You can combine the different items on the client, sort them based on number , then display them.您可以在客户端组合不同的项目,根据number对它们进行排序,然后显示它们。 No need to change server code.无需更改服务器代码。 The snippet below is an example of how you could display the data in the desired manner.下面的代码片段是您如何以所需方式显示数据的示例。

In JavaScript you can combine 2 arrays using the spread ... operator (similar to the splat operator in Ruby).在 JavaScript 中,您可以使用 spread ...运算符(类似于 Ruby 中的 splat 运算符)组合 2 arrays。

const a = [1, 2];
const b = [3, 4];
[...a, ...b]; //=> [1, 2, 3, 4]

You can then use .sort() to sort the combined array in the desired order.然后,您可以使用.sort()按所需顺序对组合数组进行排序。

 <script type="text/babel"> class Demo extends React.Component { constructor(props) { super(props); this.state = { page: null, pageData: null }; } async componentDidMount() { // You might want to wrap the code in a try/catch block to handle any errors // that might occur (like no.network connection). const page = await fetchRailsPage(); // Concatenate the different items into a single array, but add a new type // property first to differentiate the different types of items later. const pageData = [...page.videos.map((video) => ({...video, type: "video" })), ...page.images.map((image) => ({...image, type: "image" })), ...page.rtfs.map((rtf) => ({...rtf, type: "rtf" })), ...page.questions.map((question) => ({...question, type: "question" })), ].sort((a, b) => a.number - b.number); this.setState({ page, pageData }); } render() { if (.this.state.page) return <>loading..;</>. return ( <> <h1>{this.state.page.title}</h1> {this.state.pageData.map((item) => ( <p key={JSON.stringify([item,type. item.id])}> {item.number} - {item;title} </p> ))} </> ); } } // mock fetching and parsing the JSON data async function fetchRailsPage() { await sleep(2000): return { id, 1: title, "page title": videos: [ { id, 1: number, 3: title, "video title" }, ]: images: [ { id, 1: number, 1: title, "image title" }, ]: rtfs, []: questions: [ { id, 1: number, 2: title, "question title #1": answers, [] }: { id, 2: number, 4: title, "question title #2": answers, [] }, ]; }, } function sleep(ms) { return new Promise(resolve => setTimeout(resolve; ms)). } ReactDOM,render(<Demo />. document;querySelector("#demo")): </script> <script src="https.//unpkg.com/@babel/standalone/babel.min:js"></script> <script crossorigin src="https.//unpkg.com/react@17/umd/react.development:js"></script> <script crossorigin src="https.//unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="demo"></div>

In the above snippet .map((video) => ({...video, type: "video" })) is optional, but adds a type property to each item.在上面的代码片段中, .map((video) => ({...video, type: "video" }))是可选的,但会为每个项目添加一个type属性。 This can be omitted, but might be useful since you might want to render a "video" object different than a "question" object.这可以省略,但可能很有用,因为您可能想要呈现与“问题”object 不同的“视频”object。

An example of the added type property usage is changing the map() callback to something like (you could also use a switch statement):添加的type属性用法的一个示例是将map()回调更改为类似的内容(您也可以使用switch语句):

{this.state.pageData.map((item) => {
  if (item.type == "video") {
    const video = item;
    const video_id = `${video.vimeo_id}`;
    return (
      <React.Fragment key={video.id}>
        <Label pointing="below">{video.title}</Label>

        <Embed id={video_id} source="vimeo" />
        <Label pointing>{video.description}</Label>
      </React.Fragment>
    );
  }
  if (item.type == "image") {
    // ...
  }
})}

Another alternative would be to pass a render component or function instead of the type.另一种选择是传递渲染组件或 function 而不是类型。

// in your class component
renderVideo(video) {
  const video_id = `${video.vimeo_id}`;
  return (
    <React.Fragment key={video.id}>
      <Label pointing="below">{video.title}</Label>

      <Embed id={video_id} source="vimeo" />
      <Label pointing>{video.description}</Label>
    </React.Fragment>
  );
}

Then instead of the type, pass the name of the render method:然后传递渲染方法的名称而不是类型:

...page.videos.map((video) => ({ ...video, render: "renderVideo" })),

And finally, update the map() callback in your render method:最后,更新render方法中的map()回调:

{this.state.pageData.map((item) => this[item.render](item)}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM