"cannot return value referencing temporary value"

I'm making a program using Dioxus. I have the following code:

fn app(cx: Scope) -> Element {
    let posts = use_ref(cx, || load_posts(POSTS_DIR.into()).unwrap());
    let mut post_str = use_ref(cx, String::new);

    let posts_lock = posts.read();
    let posts_rendered = posts_lock.iter().map(|post| {
        rsx!(div {
            dangerous_inner_html: post.clone().as_str(),
            p{}
        })
    });

    cx.render(rsx!(
        posts_rendered,
    ))
}

But the line where I set dangerous_inner_html throws the error in the title. I think it's because I need to pass &str instead of a String to the attribute, but I can't find an appropriate work-around. If I just pass a String, it doesn't accept it, but it does say:

help: the trait `IntoAttributeValue<'a>` is implemented for `&'a str`

However, I don't have really any experience with lifetimes and I have no clue how to use that.

Any help is appreciated.

Please run cargo check and post the entire error message block, not just selected lines from it. That way we have more details about exactly where the error is arising from.

2 Likes

You might need to provide more details. Usually, if possible, a way to reproduce an error message is appreciated; and in any case at least post the whole error message, will you? In case you’re stuck in some IDE, go out to the terminal, run cargo check or cargo run or so, and fetch the whole error from there.

My reproduction attempts so far end at (POSTS_DIR and) load_posts being unknown, so I have no idea which types are involved here. Furthermore, it’s hard to judge the exact behavior of the rsx macro here, as I didn’t manage so far to find good online documentation for it.

In any case, I would also be interested whether the error changes if you leave out the .clone() step and just did post.as_str() or something like that.

1 Like

Full error without .clone():


error[E0515]: cannot return value referencing local variable `posts`
  --> src\main.rs:25:5
   |
19 |       let posts_rendered = posts.iter().map(|post| {
   |                            ------------ `posts` is borrowed here
...
25 | /     cx.render(rsx!(
26 | |         posts_rendered,
27 | |     ))
   | |______^ returns a value referencing data owned by the current function

Full error with .clone():

error[E0515]: cannot return value referencing temporary value
  --> src\main.rs:20:9
   |
20 | /         rsx!(div {
21 | |             dangerous_inner_html: post.clone().as_str()
   | |                                   ------------ temporary value created here
22 | |         })
   | |__________^ returns a value referencing data owned by the current function
   |
   = note: this error originates in the macro `rsx` (in Nightly builds, run with -Z macro-backtrace for more info)

Ah, that’s a bit ugly, I just noticed that they (dioxus) suggest writing their signature fn app(cx: Scope) -> Element despite the fact that it’s actually truly a signature fn app(cx: Scope<'_>) -> Element<'_>. Hidden lifetime for the win; I did manage to reproduce the thing in the meantime and switching to post.as_str(), changes the error to

error[E0515]: cannot return value referencing local variable `posts_lock`
  --> src/main.rs:27:5
   |
20 |       let posts_rendered = posts_lock.iter().map(|post| {
   |                            ----------------- `posts_lock` is borrowed here
...
27 | /     cx.render(rsx!(
28 | |         posts_rendered,
29 | |     ))
   | |______^ returns a value referencing data owned by the current function

which only makes sense if the return type can contain references to begin with… anyways, let me see if I can spot any obvious solutions in their API. (Also it’s slightly different from what you get… do you mind sharing what the exact return type of load_posts is? I guessed something akin to a Result<Vec<String>, …>, but maybe I’m way off)

Thank you. Something I noticed is that the problem only occurs when I need to use .as_str(): For example, this works just fine:

fn app(cx: Scope) -> Element {
    let posts = load_posts(POSTS_DIR.into()).unwrap();
    //let posts = use_ref(cx, || load_posts(POSTS_DIR.into()).unwrap());
    let posts_rendered = posts.iter().map(|post| {
        rsx!(div {
            p {post.clone()}
        })
    });

    cx.render(rsx!(
        posts_rendered,
    ))
}

If you're like me and don't have the attention to play "spot the difference" in code, the difference here is that I just put a p{} element inside the div containing a clone of the post variable, which is a String here. Which would be great, if that was what I needed.

What I'm specifically trying to do is convert a .md file (markup) to HTML and then render that, so that I can format blog posts (what I'm trying to do is make a generic blog). This seems like a generic enough use case, but I've been working on this since yesterday, scouring the API, and I can't find anything on it. Just finding out that the dangerous_inner_html attribute exists was a small miracle.

It's a little hacky TBH, but I can't for the life of me find a better solution.

Oops, I just realized you asked the return type of load_posts(). I'm really tired, sorry. Your guess was right, it's Result<Vec>.

One quick question. As use_ref seems to be for mutable state, is it necessary for the posts information to be mutable? Otherwise, the lifetimes problem seems more avoidable. (Edit: Excuse if this question seems stupid, I’m not really understanding much of the logic going on here in the first place, this is my first time seeing this framework.)

Also, I just now noticed this section in the docs which looks potentially very relevant for your code here!

FYI, I’ll be offline for the night relatively soon (time zones, yay! :slight_smile: )

It isn't necessary right now, but it probably will be in the future, since I don't want to restart the program after making a new post.

And I tried the solution in the docs, but, well, I just got even more errors. First it wanted lifetime specifiers, so I added them (this was after I moved the relevant code to its own function, it was only part of the main app() function originally for testing), but then it gave the exact same error, so I tried cloning the post variable, and then it gave "temporary value dropped while borrowed" when I called posts.read(). Bleh.

And goodnight, thanks for helping me out :3

There‘s also use_state which seems more lenient with the lifetimes, at the cost of requiring you to build a new Vec if you want to modify the state at some point.

fn app(cx: Scope) -> Element {
    let posts = use_state(cx, || load_posts(POSTS_DIR.into()).unwrap());
    let mut post_str = use_ref(cx, String::new);

    let posts_rendered = posts.iter().map(|post| {
        rsx!(div {
            dangerous_inner_html: post.as_str(),
            p{}
        })
    });

    cx.render(rsx!(
        posts_rendered,
    ))
}

Just tried converting it to use_state, no kebob :frowning:

The kind of code above with use_state compiles for me – feel free to share your error message

Huh? Weird. The code:

pub fn home<'a>(cx: Scope<'a>, posts: &'a UseState<Vec<String>>) -> Element<'a> {
    let binding = posts.clone();
    let items = binding.iter().map(|post| {
        let static_post_str: &'static str = post.clone().as_str();
        cx.render(rsx!(
            div {
                dangerous_inner_html: static_post_str
            }
        ))
    });

    cx.render(rsx!(
        items,
    ))
}

The error:

error[E0716]: temporary value dropped while borrowed
  --> src\elements.rs:20:45
   |
20 |         let static_post_str: &'static str = post.clone().as_str();
   |                              ------------   ^^^^^^^^^^^^         - temporary value is freed at the end of this statement
   |                              |              |
   |                              |              creates a temporary value which is freed while still in use
   |                              type annotation requires that borrow lasts for `'static`

I'm about to take a test (cries) so I won't be on for a while, probably

Wait, I just realized that was with me adding 'static. After removing the type annotation for static_post_str, I get the error:

error[E0515]: cannot return value referencing temporary value
  --> src\elements.rs:21:9
   |
20 |           let static_post_str = post.clone().as_str();
   |                                 ------------ temporary value created here
21 | /         cx.render(rsx!(
22 | |             div {
23 | |                 dangerous_inner_html: static_post_str
24 | |             }
25 | |         ))
   | |__________^ returns a value referencing data owned by the current function

I don't have the .clone() :wink:

This works https://www.rustexplorer.com/b/i8jhf1

pub fn home<'a>(cx: Scope<'a>, posts: &'a UseState<Vec<String>>) -> Element<'a> {
    let items = posts.iter().map(|post| {
        let post = &**post;
        cx.render(rsx!(
            div {
                dangerous_inner_html: post
            }
        ))
    });

    cx.render(rsx!(
        items,
    ))
}

Since we have &'a str: IntoAttributeValue<'a>, just convert the post: &String to &str and the problem is solved.

Thank you both so much, you're my saviors :pray: